探索字符与字符串:基本库函数的使用(一)

简介: 探索字符与字符串:基本库函数的使用(一)

前言

感谢您阅读我的博客。在本期文章中,我将为您介绍一些常用的字符和字符串处理函数,并提供一些注意事项和实现方法。


本期我们将会对以下库函数进行重点介绍以及模拟实现,其他的我们也会介绍使用方法以及注意事项。

求字符串长度

strlen

长度不受限制的字符串函数

strcpy

strcat

strcmp

内存操作函数

memcpy

memmove

函数介绍

strlen

函数原型:

size_t strlen ( const char * str );

字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0')。

参数指向的字符串必须要以 '\0' 结束

注意函数的返回值为size_t,是无符号的( 易错 ),我们在使用strlen函数时要格外注意,例如以下代码:

int main()
{
  const char* str1 = "abcdef";
  const char* str2 = "aaa";
  if (strlen(str2) - strlen(str1) > 0)
  {
    printf("str2>str1\n");
  }
  else
  {
    printf("srt1>str2\n");
  }
  return 0;
}

我们可以判断出str1长度是大于str2的,可是最终的输出为:str2>str1,这是因为size_t,是无符号的,两个无符号的数据进行相减,最终结果也会是无符号的。

所以在使用的过程中要格外注意,避免这样直接做差来判断字符串(可以将类型转换为int类型再做差),视情况而定。

strcpy

函数原型:

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

strcpy函数的作用是字符拷贝,destination为目标字符串,source为源字符串,将字符串source拷贝到destination目标字符串。

另外在使用时我们还要注意以下几点:

  • 源字符串必须以 '\0' 结束。
  • 会将源字符串中的 '\0' 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可修改
  • 目标空间必须可修改,举个例子:
int main()
{
  char arr1[] = "Hello world!";
  char* arr2 = "xxxxxxxxxxxxxxxxxxx";
  printf("%s\n", strcpy(arr2, arr1));
  return 0;
}

这里的arr2确实指向一个字符串,但arr2的字符串属于常量字符串是不可以修改的。那么这样使用必然会使程序崩溃。

strcat

函数原型:

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

strcat函数的作用是连接两个字符串 ,将source这个源字符串追加到destination目标字符串的末尾。

注意事项:

  • 源字符串必须以 '\0' 结束,连接的过程中会将源字符串末尾的\0一同拷贝过去,作为字符串结束标志。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改。
  • 同一个数组字符串不可以自己给自己追加。即
strcat(arr, arr);

在某些编译器上或许能够运行成功,但是会出现使用未初始化的内存空间这样的警告,这样的操作是很危险的,所以还是建议尽量不要这样去用,至于为什么我会在模拟实现的时候向大家介绍原因。

strcmp

函数原型:

int strcmp ( const char * str1, const char * str2 );

strcmp的作用时比较两个2字符串大小。

比较规则:

  • 第一个字符串大于第二个字符串,则返回大于0的数字
  • 第一个字符串等于第二个字符串,则返回0
  • 第一个字符串小于第二个字符串,则返回小于0的数字

那两个字符串是如何比较的呢?

strcmp函数会逐个比较两个字符串对应位置上的字符的ASCII码大小,直到遇到不相等的字符或者遇到字符串结束符'\0'。如果遇到不相等的字符,则返回两个字符的ASCII码差值;

我们来举例使用一下:

int main()
{
  int ret = strcmp("abcdef", "abc");//1
  int ret1 = strcmp("abcdef", "bbc");//-1
  int ret2= strcmp("abc", "abc");//0
  return 0;
}
  • 第一个比较,前三个字符相等到第四个字符对应位置进行比较,d和\0进行比较,‘d’>‘\0’所以返回大于0的数。
  • 第二个,两字符串第一个字符就不一样,那就对第一个字符进行比较,‘b'>‘a’所以返回小于0的数-1.
  • 第三个,两字符串相等,返回0。

strncpy

函数原型:

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

作用:

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

我们举例使用一下:

int main()
{
  char arr[20] = "abcdef";
  char arr1[] = "xxxxxxxxxxxxxxxx";
  strncpy(arr, arr1, 3);
  return 0;
}

通过调试我们发现也确实只拷贝过去了三个。除此之外还有我们的strncat和strncmp

strncat

函数原型:

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

规则如下:

  • 将源字符串src的前n个字符(或者直到遇到源字符串的结束符'\0')追加到目标字符串dest的末尾
  • 追加完成后,目标字符串dest的末尾会自动添加一个结束符'\0

使用实例:

int main()
{
  char arr[20] = "abcdef";
  char arr1[] = "xxxxxxxxxxxxxxxx";
  strncat(arr, arr1, 3);
  return 0;
}

将3个xxx添加到abcdef后边。

strncmp

函数原型:

int strncmp ( const char * str1, const char * str2, size_t num );

str1和str2是要比较的两个字符串,num是要比较的最大字符数。

比较规则和strcmp规则相同。

使用实例:

int main()
{
  char arr[] = "abcdef";
  char arr1[] = "abddd";
  printf("%d",strncmp(arr, arr1, 3));
  return 0;
}

strstr

函数原型:

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

作用:用于在一个字符串中查找指定子串的第一次出现位置。

规则如下:

  • 在字符串中查找子串的第一次出现位置。
  • 如果找到了子串,则返回指向该位置的指针。
  • 如果未找到子串,则返回NULL。

使用实例:

int main()
{
  char a[] = "abcdefjhidef";
  char b[] = "def";
  printf("%s", strstr(a, b));//defjhidef
  return 0;
}

strtok

函数原型:

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

这个函数有点奇怪,和我们平常使用的库函数都有所不同,这个函数的作用是切割字符串,具体怎么切割,规则如下:

  • 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
  • strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
  • strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  • strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
  • 如果字符串中不存在更多的标记,则返回 NULL 指针。

什么意思呢?接下来我会用代码向大家展示:

int main()
{
  char arr[] = "hello$world@haha";
  char tarr[30];
  strcpy(tarr, arr);
  char sep[] = "$@";
  char* ret=strtok(tarr, sep);
  printf("%s", ret);//hello
  return 0;
}

这段代码的输出是hello,sep是一个存放分割标记的数组,当在数组tarr中检查到sep中的字符时,strtok函数就会将该字符替换成\0,并返回到起始位置(字符串首元素地址处)。

如果再次调用该函数,传进去一个空指针:

int main()
{
  char arr[] = "hello$world@haha";
  char tarr[30];
  strcpy(tarr, arr);
  char sep[] = "$@";
  char* ret=strtok(tarr, sep);
  ret = strtok(NULL, sep);
  printf("%s", ret);//world
  return 0;
}

它的输出就是world,从第一个切割标记的字符$那里开始,查找下一个标记处,将标记改位\0,返回本次函数调用标记的起始位置。直到遇到\0为止,返回一个空指针。

在使用时我们也可以这样使用:

int main()
{
  char arr[] = "hello$world@haha*666";
  char tarr[30];
  strcpy(tarr, arr);
  char sep[] = "$@*";
  char* ret = NULL;
  for (ret = strtok(tarr, sep); ret != NULL; ret = strtok(NULL, sep))
  {
    printf("%s\n", ret);
  }
  return 0;
}

将ret=strtok(tarr, sep);作为初始值标记第一个分割点,ret != NULL;作为条件,ret = strtok(NULL, sep)作为自增量,这样不管我们是否知道需要分割的字符串被分割的次数,都可以将字符串根据自己的需求进行分割。

memcpy

函数原型:

void * memcpy ( void * dest, const void * src, size_t n );

作用:将指定长度的数据从源内存地址复制到目标内存地址。dest是目标内存地址,src是源内存地址,n是要复制的字节数。

规则如下:

  • 将源内存地址src中的前n个字节的数据复制到目标内存地址dest中。
  • 如果源内存地址和目标内存地址有重叠,复制的结果是不确定的。

就是说如果将一个数组的片段,复制给同一个数组,就可能会导致复制重叠,无法达到我们预期的结果,不同的编译器结果可能也不相同。

例如:

int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
memcpy(arr + 2, arr, 20);

这样写可能会导致复制结果出错,建议不要这样去使用。

使用实例:

#include<string.h>//使用memcpy函数要引用头文件
int main()
{
  int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
  int arr1[20] = { 0 };
  memcpy(arr1, arr, 20);
  for (int i = 0; i < 20; i++)
  {
    printf("%d ", arr1[i]);
  }
  return 0;
}

memmove

函数原型:

void * memmove ( void * destination, const void * source, size_t num );

使用规则如下:

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

使用实例:

int main()
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
  memmove(arr + 2, arr, 20);
  for (int i = 0; i < 10; i++)
  {
    printf("%d ", arr[i]);//1 2 1 2 3 4 5 8 9 10
  }
  return 0;
}

memcmp

函数原型:

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

作用:

比较两个内存区域的内容是否相等。

其中ptr1和ptr2是要比较的两个内存区域的起始地址,num是要比较的字节数

比较规则如下:

  • 比较两个内存区域的前n个字节的内容。
  • 如果两个内存区域的内容相等,返回0。
  • 如果两个内存区域的内容不相等,返回两个不相等字节的差值(按字节的无符号比较)

需要注意:

memcmp函数比较的是字节内容,而不是字符内容。因此,对于包含非字符数据(如结构体、数组等)的内存区域,也可以使用memcmp进行比较。

使用实例:

int main()
{
  int arr[] = { 1,2,1,4,5 };
  int arr1[] = { 1,2,257 };
  int ret=memcmp(arr, arr1, 9);
  printf("%d", ret);//0
  return 0;
}

我们比较前9个字节的内存返回值为0,说明两数组前9个字节的内容相等。

通过调试我们也可以观察到:


总结

好的文章到这里内容到此就结束了,在学习字符和字符串处理函数的过程中,我们不仅需要掌握其使用方法,还需要了解其背后的原理和细节。希望本篇文章能够激发您对字符和字符串处理的兴趣,让您深入探究其中的奥秘。最后,感谢您的耐心阅读。如果您想了解更多关于字符和字符串处理的知识,请继续关注我的博客,下期我将对一些基本的库函数进行模拟实现。

相关文章
|
2月前
|
存储 C语言
字符输入输出函数
字符输入输出函数
23 2
|
9月前
|
存储 算法
探索字符与字符串:基本库函数的使用(二)
探索字符与字符串:基本库函数的使用(二)
24 0
|
9月前
|
C语言
字符、字符串函数与内存函数 2
字符、字符串函数与内存函数
17 0
|
9月前
|
存储 安全 编译器
C语言字符及字符串讲解
C语言字符及字符串讲解
238 0
|
2月前
|
C语言
C语言—字符函数与字符串函数(字符问题变简单的关键之技)
C语言—字符函数与字符串函数(字符问题变简单的关键之技)
25 0
字符串函数和字符串
字符串函数和字符串
|
2月前
|
安全 Unix Linux
【C/C++ 字符串】探索C语言之字符串分割函数:strtok和strsep的区别
【C/C++ 字符串】探索C语言之字符串分割函数:strtok和strsep的区别
32 0
|
11月前
|
C语言 C++
C语言/关于字符和字符串的库函数
C语言/关于字符和字符串的库函数
|
12月前
字符+字符串函数 一
字符+字符串函数
31 0
|
8月前
|
算法 编译器 C语言
有关字符串的那些库函数
有关字符串的那些库函数