上章我们简单介绍了几个字符串函数,这里先补充几个。
嘿咻咻咻咻咻,鸡汤来咯。
1.strtok
char * strtok( char * str, const char * sep);
这个是cplusplus上的介绍,简单介绍:
sep 参数是个字符串,定义了用作分隔符的字符集合。
第一个参数指定一个字符串,它包含了 0 个或者多个由 sep 字符串中一个或者多个分隔符分割的标 记。
strtok 函数找到 str 中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注: strtok函数会改变被操作的字符串,所以在使用 strtok 函数切分的字符串一般都是临时拷贝的内容 并且可修改。)
strtok 函数的第一个参数不为 NULL ,函数将找到 str 中第一个标记, strtok 函数将保存它在字符串 中的位置。
strtok 函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标 记。
如果字符串中不存在更多的标记,则返回 NULL 指针。
如果我们有这样一个字符数组
char ch[ ] = "abcdefgh.ijk";
我想要拿到abc,用数组也可以达到我们预想的效果,用strtok也可以拿到,上代码:
#include <stdio.h> #include <string.h> int main() { char ch[] = "abcdefgh.ijk"; char buff[200]; srtcpy(buff, ch); const char* p = ".";//可以作为分割符的字符的集合,可以是多个 strtok(buff,p);//这个函数就是一个分割符,把我们的字符串分割成n段 //该函数每次找到p中的其中一个字符(一个标记),就将该字符改成'\0',并返回指向这个标记的指针,这里就是a的地址 //(注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容 并且可修改。) //所以我们用另一个字符数组来拷贝ch return 0;
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> int main() { char ch[] = "abcdefgh.ijk"; char buff[200]; strcpy(buff, ch); const char* p = "."; char* str = strtok(buff, p);//strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串 中的位置。 printf("%s\n", str); char* str1 = strtok(NULL, p);//第二次使用时保存了上一次使用保存好的位置开始继续查找,然后返回这个字段的启示位置。 printf("%s\n", str1); return 0; }
结果如下:
2. strerror
strerror返回错误码,所对应的错误信息。
解释 errnum 的值,生成一个字符串,其中包含一条消息,该消息描述错误条件,就好像库的函数设置为 errno 一样。
返回的指针指向静态分配的字符串,程序不得修改该字符串。对此函数的进一步调用可能会覆盖其内容(不需要特定的库实现来避免数据争用)。
拿计算机跑一跑:
我们传参 0 1 2 3 4都有自己的意义。这里的0 1 2 3 4 都是错误码,比如浏览网站时会看见 404 等。
3.字符分类函数:
这里有很多经常使用的库函数:
4.内存函数
4.1memcpy
mem —> memory 记忆,但是在我们计算机语言中一般翻译为内存。
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。 这个函数在遇到 '\0' 的时候并不会停下来。 如果source和destination有任何的重叠,复制的结果都是未定义的。
它和strcpy很像,但是不一样。我们strcpy只能拷贝字符串,我们看memcpy的参数,都是void*型的,所以我们可以是任意类型。
我们用int类型试一试:
#include <stdio.h> #include <string.h> int main() { int arr1[] = { 0,1,2,3,4,5,6,7,8,9 }; int arr2[10]; memcpy(arr2, arr1, 40); for (int i = 0; i < 10; i++) { printf("%d ", arr2[i]); } return 0; }
memcpy第三个参数的单位是字节,所以我这里写的是40。
4.2 memmove
将数字字节的值从源指向的位置复制到目标所指向的内存块。复制就像使用了中间缓冲区一样进行,从而允许目标和源重叠。
源指针和目标指针所指向的对象的基础类型与此函数无关;结果是数据的二进制副本。
该函数不检查源代码中的任何终止空字符 - 它始终精确复制数字字节。
为避免溢出,目标和源参数所指向的数组大小应至少为数字字节。
可以说memmove是memcpy的一部分。
它和 memcpy 的差别就是 memmove 函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用 memmove 函数处理。
我们写一段代码来试试自己给自己拷贝,看看结果如何:
先看看模拟实现的memcpy:
#include <stdio.h> #include <string.h> #include <assert.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; } int main() { int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; my_memcpy(arr1+2, arr1, 20); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr1[i]); } return 0; }
再来看看memmove 的结果:
#include <stdio.h> #include <string.h> int main() { int arr[] = { 0,1,2,3,4,5,6,7,8,9 }; memmove(arr+2, arr, 20); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } return 0; }
4.3memcmp
比较从ptr1和ptr2指针开始的num个字节
我们重点来看它的返回值:
对于strcmp相比,memcmp的参数是不固定的,而strcmp的参数都是const chat* 类型。 相比之下memcmp功能更加强大。
我们跑一段代码试试:
#include <stdio.h> #include <string.h> int main() { char buffer1[] = "DWgaOtP12df0"; char buffer2[] = "DWGAOTP12DF0"; int n; n = memcmp(buffer1, buffer2, sizeof(buffer1)); if (n > 0) printf("'%s' is greater than '%s'.\n", buffer1, buffer2); else if (n < 0) printf("'%s' is less than '%s'.\n", buffer1, buffer2); else printf("'%s' is the same as '%s'.\n", buffer1, buffer2); return 0; }
4.4 memset
顾名思义memset是内存设置函数,这个函数作为补充,想要了解更多,可以查cplusplus.com
这是未调用memset之前的内存。
这是调用之后的内存。