4.2 strtok
char* strtok(char* str,const char* delimiters);
对有分割符的字符串操作,将它们分隔开来。
用法:
delimiters参数是个字符串,定义了用作分隔符的字符集合
第一个参数指定一个字符串,它包含了0个或者多个由delimiters字符串中一个或者多个分隔符分割的标记。
strtok函数找到str中的下一个标记,并将其用'\0'结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,把它修改为'\0',strtok函数将保存它在字符串中的位置。strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多的标记,则返回NULL指针。
示例:
#include<stdio.h> #include<string.h> int main() { char arr[] = "xilanhua@csdn.net"; char buf[30] = { 0 }; strcpy(buf, arr);//后面操作buf,不会修改原数据 const char* p = "@.";//const 更严谨,分割符的字符合集 char* str = strtok(buf, p);//传入buf不为空,返回最开始的地址'x',把第一个分割符'@'改为'\0',并保存第一个分割符'@'的位置 printf("%s\n", str); str = strtok(NULL, p);//传入空指针,返回刚才保存的位置下一个字符位置'c',从刚刚保存的位置开始寻找下一个分割符'.',改为'\0',保存这个位置。 printf("%s\n", str); str = strtok(NULL, p);//传入空指针,返回刚才保存的位置下一个字符位置's',从刚刚保存的位置开始寻找下一个分割符'\0',保存这个位置 printf("%s\n", str); str = strtok(NULL, p);//返回空指针 return 0; }
可以发现这样有很多重复代码,我们可以利用如果字符串中不存在更多的标记,则返回NULL指针,这条性质,循环打印
#include<stdio.h> #include<string.h> int main() { char arr[] = "xilanhua@csdn.net"; char buf[30] = { 0 }; strcpy(buf, arr);//后面操作buf,不会修改原数据 const char* p = "@.";//const 更严谨 char* str = NULL; for (str = strtok(buf, p); str != NULL; str = strtok(NULL, p))//最后会strtok返回NULL { printf("%s\n", str); } return 0; }
可以发现strtok函数有记忆功能,可以记住上次调用保存的位置,那么可以说明使用了静态变量。
5.错误信息报告
5.1 strerror
char* strerror(int errnum);
返回错误码errnum所对应的错误信息。
每个错误码都有对应的错误信息。
示例:
C语言的库函数在调用失败的时候,会将一个错误码存放在一个叫:errno的变量中
当我们想知道调用库函数的时候发生了什么错误信息
就可以将:errno中的错误码翻译成错误信息,使用时要包含头文件<errno.h>
没有错误是0
在文件操作时的使用情况。
perror 函数相当于printf 函数和 strerror 函数一起使用的效果。
6.字符操作
以下函数都要包含头文件 <ctype.h>
字符分类函数:
字符转换函数:
1. int tolower(int c);//转换为小写 2. int toupper(int c);//转换为大写
7.内存操作函数
字符串相关函数都是对字符串进行操作的,而下面函数都是对内存直接操作的函数,也需要包含头文件<string.h>。
7.1 memcpy
内存拷贝函数
void* memcpy(void* destination,const void* source,size_t num);
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到'\0'的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是C语言标准未定义的。有重叠的应该使用memmove函数
示例:
#include<stdio.h> #include<assert.h> #include<string.h> int main() { int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; int arr2[8] = { 0 }; //把arr1中的前五个数据拷贝到arr2中 是整形不能用strcpy memcpy(arr2,arr1,20);//从arr1中拷贝20个字节放到arr2中 for (int i = 0; i < 8; i++) { printf("%d ", arr2[i]); } return 0; }
自己模拟实现memmove函数:
void* my_memcpy(void* destination, const void* source, size_t num) { void* ret = destination; assert(destination && source); while (num--) { *(char*)destination = *(char*)source; destination = (char*)destination + 1; source = (char*)source + 1; } return ret; }
7.2 memmove
void* memmove(void* destination,const void* source,size_t num);
- 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
- 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
当我们拷贝有重叠部分的内容时,比如:
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; memcpy(arr1 + 2, arr1, 20);
可能会出现这种情况,没有达到想要的效果
所以要使用memcpy函数
#include<stdio.h> #include<string.h> int main() { int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; memmove(arr1 + 2, arr1, 20); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr1[i]); } }
自己模拟实现memmove函数
void* my_memmove(void* dest, const void* src, size_t num) { void* ret = dest; assert(dest && src); if (dest > src)//从后往前拷贝 { while (num--) { *((char*)dest + num) = *((char*)src + num); } } else//从前往后拷贝 { while (num--) { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } } return ret; }
注意:
在内存重叠的时候,使用memcpy可能会出现意想不到的结果建议在内存重叠的情况,使用memmove函数
C语言:memcpy拷贝不重叠的内存,重叠的就交给memmove
memmove 包含 memcpy 的功能
vs上可以使用memcpy操作重叠内容,但不能保证其他编译器可以。
7.3 memset
void* memset(void* ptr, int value, size_t num);
将ptr指向的空间的前num个字节设置为value,以字节为单位设置内存。
示例:
7.4 memset
int memcmp(const void* ptr1, const void* ptr2, size_t num);
比较从ptr1和ptr2指针开始的num个字节
返回值如下 :与 strcmp 和 strncmp 都类似
示例:
#include<string.h> #include<stdio.h> int main() { int arr1[] = { 1,2,3,4,5 }; int arr2[] = { 1,2,3,4,6 }; int ret = memcmp(arr1, arr2, 16); printf("%d\n", ret);//0 相等 ret = memcmp(arr1, arr2, 17); printf("%d\n", ret);//小于0 return 0; }
本篇结束