(2)strerror的使用
#include<stdio.h> #include<string.h> int main() { printf("%s\n", strerror(0)); printf("%s\n", strerror(1)); printf("%s\n", strerror(2)); printf("%s\n", strerror(3)); printf("%s\n", strerror(4)); return 0; }
#include<stdio.h> #include<string.h> #include<errno.h> int main() { FILE* pf = fopen("test.txt", "r"); if (pf == NULL) { printf("%s\n", strerror(errno)); return 0; } fclose(pf); return 0; }
(3)perror的使用
perror和strerror很相似,区别就是它是可以自己打印出错误信息的
perror在打印错误信息之前,会先打印出自定义的信息。
perror==printf+strerror
#include<stdio.h> int main() { FILE* pf = fopen("test.txt", "r"); if (pf == NULL) { perror("fopen"); return 0; } fclose(pf); return 0; }
二、字符函数
对于这部分的函数,我们用的很少,当我们想要使用的时候,直接去文档搜索一下用法即可
1.字符分类函数
函数 | 如果它的参数符合下列条件则返回真 |
iscntrl | 任何控制字符 |
isspace | 空白字符:空格' ',换页'\f',换行'\n',回车'\r',制表符’\t‘,垂直制表符’\v‘ |
isdigit | 十进制数0~9 |
isxdigit | 十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F |
islower | 小写字母a~z |
isupper | 大写字母A~Z |
isalpha | 小写字母a~z,或者A~Z |
isalnum | 字母或数字,a~z,A~Z,0~9 |
ispunct | 标点符号,任何不属于数字或者字母的图形字符(可打印) |
isgraph | 任何图形字符 |
isprint | 任何可打印字符,包括图形字符和空白字符 |
2.字符转换函数
注意:这两个函数不会改变自身本来的值,是返回转换后的值
大写转小写 | int tolow(int c) |
小写转大写 | int toupper(int c) |
3.利用字符函数,将字符串中的大写字母改为小写打印出来
#include<stdio.h> #include<string.h> #include<ctype.h> int main() { char arr[] = "I Have An Apple"; int i = 0; int len = strlen(arr); for (i = 0; i < len; i++) { if (isupper(arr[i])) { arr[i] = tolower(arr[i]); } printf("%c", arr[i]); } return 0; }
三、内存函数
我们已经有了字符串的操作函数,但是这些函数只针对字符串,我们有时候需要对整型数组等进行字符串类似的操作。所以我们就需要使用内存函数
1.memcpy
(1)memcpy的库函数文档
它有三个参数,第一个参数是目标空间的起始地址,第二个参数第源头空间的地址,第三个变量是拷贝num个字节
我们这个函数的功能是将source的前num个字节拷贝到destination中
返回一个指针指向dest处的指针,这个指针是void类型的
(2)memcpy的使用以及注意事项
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到 '\0' 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。
#include<stdio.h> #include<string.h> int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 }; int arr2[10] = { 0 }; memcpy(arr2, arr1, 20); return 0; }
#include<stdio.h> #include<string.h> int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 }; int arr2[10] = { 0 }; memcpy(arr2, arr1 + 2, 20); return 0; }
#include<stdio.h> #include<string.h> int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 }; int arr2[10] = { 0 }; memcpy(arr2, arr1 + 2, 17); return 0; }
17个字节可行的原因是因为小端存储造成的
(3)模拟memcpy函数
#include<stdio.h> #include<assert.h> void* my_memcpy(void* dest, const void* src, size_t num) { assert(dest && src); void* ret = dest; while (num--) { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } return ret; } int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 }; int arr2[10] = { 0 }; my_memcpy(arr2, arr1 + 2, 20); return 0; }
2.memmove
(1)memcpy的缺陷
在memcpy函数中,我们可以将一个地址的前n个字节复制到一个地址动。但是如果我们自身对自身进行拷贝的话,会出现一些问题
假如下图是src和dest的地址
那么按照我们的思路,最终的现象就是下图所示的
我们发现会出现1212这样似乎处于一个循环的情景,这与我们的字符串追加造成的现象是极其相似的。而且strcpy中也会出现这样的情况。为了避免出现这个现象,我们可以这样做,从后向前拷贝。
但是这样的话,如果dest又在src前面的话,又不符合我们的想法了,又会陷入一种类型于死循环的情况
这时候我们就需要从前向后拷贝了
于是我们发现,这个似乎需要分情况,经过我们的分析,我们可以得出以下结论
当然对于这四种情况,我们可以进行一次简化
如果是这样拷贝,那么我们的目标就实现了
而这个功能其实在memmove函数中就已经实现了
(2)memmove的库函数文档
这个函数的参数与memcpy是一样的,功能也是一样的,唯一不同的就是,可以自己拷贝自己了
(3)memmove的模拟实现
#include<stdio.h> #include<assert.h> void* my_memmove(void* dest, const void* src, size_t num) { assert(src && dest); void* ret = dest; if (dest < src) { //从前向后拷贝 while (num--) { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } } else { //从后向前拷贝 while (num--) { *((char*)dest + num) = *((char*)src + num); } } return ret; } int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 }; int arr2[10] = { 0 }; my_memmove(arr1, arr1 + 2, 20); return 0; }
(4)memmove的使用以及注意事项
1.和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
2.如果源空间和目标空间出现重叠,就得使用memmove函数处理。
3.在vs上memcpy和memmove没有任何区别。但是其他编译器上不一定
3.memcmp
(1)memcmp的库函数文档
它的功能是比较ptr1和ptr2两个指针所指向空间的前num个字节
ptr1>ptr2返回大于0的数
ptr1==ptr2返回0
ptr1<ptr2返回小于0的数
(2)memcmp的使用
#include<stdio.h> #include<string.h> int main() { int arr1[] = { 1,2,3 }; int arr2[] = { 1,2,5 }; int ret = memcmp(arr1, arr2, 9); printf("%d", ret); return 0; }
#include<stdio.h> #include<string.h> int main() { int arr1[] = { 1,2,3 }; int arr2[] = { 1,2,5 }; int ret = memcmp(arr1, arr2, 8); printf("%d", ret); return 0; }
#include<stdio.h> #include<string.h> int main() { int arr1[] = { 1,2,7 }; int arr2[] = { 1,2,5 }; int ret = memcmp(arr1, arr2, 12); printf("%d", ret); return 0; }
4.memset
(1)memset的库函数文档
它是一个内存设置函数
将ptr空间中的前num个字节,以字节为单位设置为value
(2)memset的使用
#include<stdio.h> #include<string.h> int main() { char arr[] = "hello world"; memset(arr, 'x', 5); printf("%s\n", arr); memset(arr + 6, 'y', 5); printf("%s\n", arr); return 0; }
#include<stdio.h> #include<string.h> int main() { int arr[10] = { 0 }; memset(arr, 1, 40); return 0; }
总结
本节讲解了最常使用的字符串函数,内存函数,字符函数的使用,以及一些重要的函数的实现
如果对你有帮助,不要忘记点赞加收藏哦!!!
想获得更多优质内容,一定要关注我哦!!!