目录
前言
函数介绍
strlen
strcpy
strcat
strcmp
strncpy
strncat
strncmp
strstr
strtok
总结
感谢您阅读我的博客。在本期文章中,我将为您介绍一些常用的字符和字符串处理函数,并提供一些注意事项和实现方法。
本期我们将会对以下库函数进行重点介绍以及模拟实现,其他的我们也会介绍使用方法以及注意事项。
求字符串长度
strlen
长度不受限制的字符串函数
strcpy
strcat
strcmp
内存操作函数
memcpy
memmove
函数原型:
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类型再做差),视情况而定。
函数原型:
char* strcpy(char * destination, const char * source );
strcpy函数的作用是字符拷贝,destination为目标字符串,source为源字符串,将字符串source拷贝到destination目标字符串。
另外在使用时我们还要注意以下几点:
int main()
{
char arr1[] = "Hello world!";
char* arr2 = "xxxxxxxxxxxxxxxxxxx";
printf("%s\n", strcpy(arr2, arr1));
return 0;
}
这里的arr2确实指向一个字符串,但arr2的字符串属于常量字符串是不可以修改的。那么这样使用必然会使程序崩溃。
函数原型:
char * strcat ( char * destination, const char * source );
strcat函数的作用是连接两个字符串 ,将source这个源字符串追加到destination目标字符串的末尾。
注意事项:
strcat(arr, arr);
在某些编译器上或许能够运行成功,但是会出现使用未初始化的内存空间这样的警告,这样的操作是很危险的,所以还是建议尽量不要这样去用,至于为什么我会在模拟实现的时候向大家介绍原因。
函数原型:
int strcmp ( const char * str1, const char * str2 );
strcmp的作用时比较两个2字符串大小。
比较规则:
那两个字符串是如何比较的呢?
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;
}
函数原型:
char * strncpy ( char * destination, const char * source, size_t num );
作用:
我们举例使用一下:
int main()
{
char arr[20] = "abcdef";
char arr1[] = "xxxxxxxxxxxxxxxx";
strncpy(arr, arr1, 3);
return 0;
}
通过调试我们发现也确实只拷贝过去了三个。除此之外还有我们的strncat和strncmp
函数原型:
char * strncat ( char * destination, const char * source, size_t num );
规则如下:
使用实例:
int main()
{
char arr[20] = "abcdef";
char arr1[] = "xxxxxxxxxxxxxxxx";
strncat(arr, arr1, 3);
return 0;
}
将3个xxx添加到abcdef后边。
函数原型:
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;
}
函数原型:
char * strstr ( const char *, const char * );
作用:用于在一个字符串中查找指定子串的第一次出现位置。
规则如下:
使用实例:
int main()
{
char a[] = "abcdefjhidef";
char b[] = "def";
printf("%s", strstr(a, b));//defjhidef
return 0;
}
函数原型:
char * strtok ( char * str, const char * sep );
这个函数有点奇怪,和我们平常使用的库函数都有所不同,这个函数的作用是切割字符串,具体怎么切割,规则如下:
什么意思呢?接下来我会用代码向大家展示:
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)作为自增量,这样不管我们是否知道需要分割的字符串被分割的次数,都可以将字符串根据自己的需求进行分割。
函数原型:
void * memcpy ( void * dest, const void * src, size_t n );
作用:将指定长度的数据从源内存地址复制到目标内存地址。dest是目标内存地址,src是源内存地址,n是要复制的字节数。
规则如下:
就是说如果将一个数组的片段,复制给同一个数组,就可能会导致复制重叠,无法达到我们预期的结果,不同的编译器结果可能也不相同。
例如:
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
memcpy(arr + 2, arr, 20);
这样写可能会导致复制结果出错,建议不要这样去使用。
使用实例:
#include//使用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;
}
函数原型:
void * memmove ( void * destination, const void * source, size_t num );
使用规则如下:
使用实例:
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;
}
函数原型:
int memcmp ( const void * ptr1, const void * ptr2, size_t num )
作用:
比较两个内存区域的内容是否相等。
其中ptr1和ptr2是要比较的两个内存区域的起始地址,num是要比较的字节数
比较规则如下:
需要注意:
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个字节的内容相等。
通过调试我们也可以观察到:
好的文章到这里内容到此就结束了,在学习字符和字符串处理函数的过程中,我们不仅需要掌握其使用方法,还需要了解其背后的原理和细节。希望本篇文章能够激发您对字符和字符串处理的兴趣,让您深入探究其中的奥秘。最后,感谢您的耐心阅读。如果您想了解更多关于字符和字符串处理的知识,请继续关注我的博客,下期我将对一些基本的库函数进行模拟实现。