字符串函数和字符串

简介: 字符串函数和字符串

一.函数介绍

1.1 strlen

size_t strlen(const char *str);


1.字符串以‘\0’作为结束标志,strlen函数返回的是在字符串中‘\0’前面出现的字符个数(不包括‘\0’)


2.函数指向的字符串必须要一‘\0’结束。


3.注意函数的返回值为size_t,是无符号的(易错)


eg:


strlen 的模拟实现

#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* arr)
{
  assert(arr);//确保为非指针
  char* start = arr;
  char* end = arr;
  while (*end != '\0')
  {
    end++;
  }
  return end - start;
}
int main()
{
  char arr[] = "abcdefg";
  int ret=my_strlen(arr);
  printf("%d", ret);
  return 0;
}

1.2 strcpy

char* strcpy(char* destination,const char* source);


1. 源字符串必须以‘\0’结束。


2.会将源字符串中的‘\0’拷贝到目标空间


3.目标空间必须足够大,以确保能存放源字符串


4.目标空间必须可变

strcpy 的模拟实现

#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
  assert(dest);
  assert(src);
  char* ret = dest;
  while (*dest++ = *src++)
  {
    ;
  }
  return ret;
}
int main()
{
  char arr1[20] = "abc";
  char arr2[] =   "hello world!";
  printf("%s\n", my_strcpy(arr1, arr2));
  return 0;
}

1.3 stract

char * stract( char * destination,const char * source);


1.源字符串与目标字符串必须以‘\0’结束


2.目标空间必须有足够大,能容纳下源字符串的内容


3.目标空间必须可修改


4.字符串不能够自己给自己追加

使用和模拟

char* my_strcat(char* dest, const char*src)
{
  //1.找目标空间中的\0
  char* cur = dest;
  while (*cur)
  {
    cur++;
  }
  //2.拷贝源头数据到\0之后的空间
  while (*cur++ = *src++)
    {
    ;
  }
 
  return dest;
}
int main()
{
  char arr1[20] = "hello";
  char arr2[] =  " world!";
    //my_strcat(arr1,arr2);
  printf("%s\n", strcat(arr1,arr2));
  return 0;
}

1.4 strcmp

int * strcmp ( const char * str1,const char * str2);(比较的为字符串中每个字符的ASCII)


1. 第一个字符串大于第二个字符串,则返回大于0的数字


2. 第一个字符串等于第二个字符串,则返回0


3.第一个字符串小于第二个字符串,则返回小与0的数字


模拟实现:

int my_strcmp(const char* s1, const char* s2)
{
  assert(s1 && s2);
  while (*s1 == *s2)
  {
    if (*s1 == '\0')
    {
      return 0;
    }
    s1++;
    s2++;
  }
  return *s1 - *s2;
}

1.5 strncpy

char * strncpy( char * destination , const char * source ,size_t num);


1. 拷贝num个字符串到目标空间


2.如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

int main()
{
  char arr1[20] = "abcdefghi";
  char arr2[] = "xxxx";
  strncpy(arr1, arr2, 8);
    printf("%s\n", arr1);
  return 0;
}

1.6 strncat

chat * strncat (char * destination , const char * source, size_t num);(可以给自己追加)

int main()
{
  char arr1[20] = "abcdef\0qqqqqq";
  char arr2[] = "xyz";
  strncat(arr1, arr2, 2);
  printf("%s\n", arr1);
  return 0;
}

1.7 strncmp

int strncmp (cnst char * str1, cnst char *str 2,size_t num);

1. int main()
{
  int ret = strncmp("abcdef", "abc", 4);
  printf("%d\n", ret);
  return 0;
}

1.8 strstr

char * strstr ( const char *str1, const char * str2);

在一个字符串中另外一个字符串是否存在,存在:返回子串第一次出现的位置;不存在,返回NULL。

int main()
{
    char arr1[] = "abcdefabcdef";
    char arr2[] = "cdef";
    char *p= strstr(arr1, arr2);
    if (p == NULL)
    {
        printf("不存在\n");
    }
    else
    {
        printf("%s", p);
    }
    return 0;
}

模拟实现:

char* my_strstr(const char* str1, const char* str2)
{
  const char* s1 = str1;
  const char* s2 = str2;
  const char* p = str1;
  if (*str2 == '\0')
  {
    return str1;
  }
  while (*p)
  {
    s1 = p;
    s2 = str2;
    while (*s1 != '\0' && *s2 != '\0' && (*s1 == *s2))
    {
      s1++;
      s2++;
    }
    if (*s2 == '\0')
    {
      return (char*)p;//找到了
    }
    p++;
  }
  return NULL;//找不到子串
}
//KMP 算法 - B站搜索:比特大博哥
//难度也比较大一些
int main()
{
  char arr1[] = "abcdefabcdef";
  char arr2[] = "cde";
 
  char* p = my_strstr(arr1, arr2);
  if (p == NULL)
  {
    printf("不存在\n");
  }
  else
  {
    printf("%s\n", p);
  }
  return 0;
}

1.9 strtok

char * strok( char * str,const char * sep);


1.sep 参数是个字符串,定义了用作分隔符的字符集合


2.第一个参数指定一个字符串,它包含了0个或者多个sep字符串中一个或者多个分隔符分割的标记。


3.strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容 并且可修改。)


4.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串 中的位置。


5.strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标 记。

6.如果字符串中不存在更多的标记,则返回 NULL 指针。

int main()
{
  char arr[] = "akai@bitedu.com";
  char buf[200] = { 0 };//"akai@bitedu.com"
  strcpy(buf, arr);
  const char* p = "@.";
  char* str = NULL;
  for (str=strtok(buf, p); str!=NULL; str=strtok(NULL, p))
  {
    printf("%s\n", str);
  }
  return 0;
}

1.10 strerror

char * strerror (int errnum)

返回错误码所对应的错误信息

使用:

//错误码记录到错误码的变量中
//errno - C语言提供的全局的错误变量
//#include <errno.h>
int main()
{
  FILE* pf = fopen("test.txt", "r");
  if (pf == NULL)
  {
    perror("可自定义");//打印的依然是errno变量中错误码对应的错误信息
    //printf("%s\n", strerror(errno));
    //printf("%s\n",errno)
    return 1;
  }
  //读文件
  fclose(pf);
  pf = NULL;
  return 0;
}

1.11 memcpy、memmove

void * memcpy ( void * destination,const void * source , size_t num)


memcpy:


1. 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。


2.这个函数在遇到 '\0' 的时候并不会停下来。


3. 如果source和destination有任何的重叠,复制的结果都是未定义的


memmove:

和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。 如果源空间和目标空间出现重叠,就得使用memmove函数处理。

#include <stdio.h>
#include <ctype.h>
void* my_memcpy(void* dest, void* src, size_t num)
{
  void* ret = dest;
  assert(dest);
  assert(src);
  while(num--)
  {
    *(char*)dest = *(char*)src;
    dest = (char*)dest + 1;
    src = (char*)src + 1;
  }
  return ret;
}
 
void* my_memmove(void* dest, void* src, size_t num)
{
  void* ret = dest;
  assert(dest);
  assert(src);
 
  if (dest < src)//1 前->后
  {
    while(num--)
    {
      *(char*)dest = *(char*)src;
      dest = (char*)dest + 1;
      src = (char*)src + 1;
    }
  }
  else //2 3 后->前
  {
    while (num--)
    {
      *((char*)dest + num) = *((char*)src + num);
    }
  }
  return ret;
}
//memcpy只需要实现不重叠的拷贝就可以了
//memmove是需要实现重叠内存的拷贝的
int main()
{
  int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
  memcpy(arr1 + 2, arr1, 20);//无法实现重叠字符串
  memmove(arr1+2, arr1, 20);
  int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
  int arr2[10] = { 0 };
  my_memcpy(arr2, arr1, 20);
  int i = 0;
  for (i = 0; i < 10; i++)
  {
    printf("%d ", arr2[i]);
  }
  return 0;
}

1、12 memcomp

int memcmp ( const void * ptr1, const void * ptr2, size_t num )


比较从ptr1和ptr2指针开始的num个字节


和strncmp类似,但接受的类型更广。


1、13 memset

void * memset (void * ptr , int value , size_t num)


ptr 所指向的内存块的前 num 个字节设置为指定的(解释为无符号字符)

#include <stdio.h>
#include <string.h>
 
int main ()
{
  char str[] = "almost every programmer should know memset!";
  memset (str,'-',6);
  puts (str);
  return 0;
}

二、字符分类函数

2.1 iscntrl

int iscntrl ( int c )

检查字符 c 是否为控制字符

#include <stdio.h>
#include <ctype.h>
int main ()
{
  int i=0;
  char str[]="first line \n second line \n";
  while (!iscntrl(str[i]))
  {
    putchar (str[i]);
    i++;
  }
  return 0;
}
//此代码逐个字符打印字符串,直到遇到破坏 while 循环的控制字符。在这种情况下,将仅打印第一行,因为
//该行以“\n”结尾,这是一个控制字符(ASCII 代码0x0a)。

2.2 isspace

int isspace(int c)

检查c是否为空白字符:空白字符:空格‘ ’,换页‘\f’,换行'\n',回车‘\r’,制表符'\t'或者垂直制表符'\v'。若是空白字符,则为真,返回大于0的数;否则为假,返回值为0;

#include <stdio.h>
#include <ctype.h>
int main()
{
    char c;
    int i = 0;
    char str[] = "Example sentence to test isspace\n";
    while (str[i])
    {
        c = str[i];
        if (isspace(c))//判断是否为空白字符
            c = '\n';//若是空白字符,将空白字符替换为'\n'
        putchar(c);
        i++;
    }
    return 0;
}

2.3 isdigit、isxdigit、 islower 、isupper、isalpha、isalnum、ispunct、isgraph、isprint、tolower、toupper

int ——(int c)


isdigit:检查是否为数字字符(十进制数0~9)


isxdigit:检查是否为十六进制数字字符


十六进制是以下任意数字:1、2、3、4、5、6、7、8、9、a、b、c、d、e、f、A、B、C、D、E、F


islower:判断 c 是否为小写字母:a~z


isupper:判断 c 是否为大写字母:A~Z


isalpha:判断 c 是否为字母:a~z   A~Z


isalnum:判断 c 是否为十进制数字或者为大、小写字母


ispunct:判断 c 是否为标点符号字符,任何不属于数字或者字母的图形字符(可打印)


isgraph:检查 c 是否为具有图形表示形式的字符,具有图形表示形式的字符是除空格字符(' ')之外可以打印的字符(由isprint确定)。


isprint:检查 c 是否为可打印字符,对于标准 ASCII 字符集(由“C”区域设置使用),打印字符的所有 ASCII 代码都大于 0x1f(美国),但 0x7f (DEL) 除外。


对于与 isprint 相同的情况,isgraph 返回 true,但空格字符 (' ') 除外,空格字符 (' ') 在用 isprint 检查时返回 true,但在使用 isprint 检查时返回 false。


tolower、toupper:转换大小写字母


相关文章
|
1月前
|
安全 C语言
需要知道的字符串函数
需要知道的字符串函数
|
1月前
字符串函数
字符串函数
|
10月前
|
存储 C语言
字符串函数介绍&应用(二)
字符串函数介绍&应用
|
10月前
|
存储 C语言
字符串函数介绍&应用(一)
字符串函数介绍&应用
|
11月前
字符+字符串函数 一
字符+字符串函数
31 0
|
1月前
|
C语言
字符函数和字符串函数
字符函数和字符串函数
56 0
|
7月前
|
编译器
C详细的字符串函数
C详细的字符串函数
38 0
|
10月前
字符函数和字符串函数详解(三)
字符函数和字符串函数详解
21 0
|
10月前
|
C语言
字符函数和字符串函数详解(一)
字符函数和字符串函数详解
31 0
|
11月前
|
C语言
一文带你玩转C库中的一系列字符串函数
一文带你玩转C库中的一系列字符串函数
52 2