字符转换
前面我们只是理解了判断字符,如果要转换字符也有对应的库函数
toupper
小写字母是以下任意字母:a b c d e f g h i j k l m n o p q r s t u v w x y z,分别翻译为:A B C D E F G H I J K L M N O P Q R S T U V W X Y Z。
#include<stdio.h> #include<string.h> #include<ctype.h> #include<stdlib.h> int main() { int i = 97; for (; i <= 122; i++) { printf("%c\n", toupper(i)); } return 0; }
如果是小写就转换,不是就不转换
tolower
同理这个函数就是把大写转换成小写
#include<stdio.h> #include<string.h> #include<ctype.h> #include<stdlib.h> int main() { int i = 65; for (; i <= 90; i++) { printf("%c\n", tolower(i)); } printf("%c\n", tolower('a')); return 0; }
如果是大写就转换,不是就不转换
内存相关函数
memcpy
前面我们已经学习过了strcpy,这个函数只适合于字符串拷贝,如果要拷贝整数数组,浮点型数组就会没办法,但是memcpy就可以解决
这个函数有三个参数,一个是目标空间,一个是起始地址,以及要拷贝的字节总大小
如果看过我模拟出来的qsrot函数就会明白,这里为啥要拷贝字节总大小,我们只把对应的字节大小进行拷贝过去
include<stdio.h> int main() { int arr[20] = { 1,2,3,4,5,6,7,8,9 }; int arr1[10] = { 0 }; memcpy(arr1, arr, sizeof(int) * 9); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } return 0; }
如果我们要模拟实现出来
#include<stdio.h> #include<string.h> #include<ctype.h> #include<stdlib.h> #include<assert.h> void* my_memcpy(void* destintion, const void* soured, size_t num) { //不为空 assert(destintion && soured); //一个一个字节进行拷贝,要使用char*, 加1访问一个字节 const char* su = soured; char* de = destintion; while (num) { *de++ = *su++; num--; } return destintion; } int main() { char arr[20] = "abcd\0f"; char arr1[10] = { 0 }; my_memcpy(arr1, arr, sizeof(arr[0]) * 10); int i = 0; for (i = 0; i < 10; i++) { printf("%c ", arr1[i]); } return 0; }
如果当我们使用这个模拟函数进行自身部分的拷贝就会发现,和库函数memcpy有差异
#include<stdio.h> #include<string.h> #include<ctype.h> #include<stdlib.h> #include<assert.h> int main() { int arr[20] = {1,2,3,4,5,6,7,8,9}; memcpy( arr + 2, arr, sizeof(arr[0]) * 5); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } return 0; }
库函数的结果
我们模拟函数的结果:
可以看出两者的差异
看到这里就会有疑问,是不是模拟错了?
其实标准值规定,memcpy来实现不重叠的内存拷贝,而重叠的内存拷贝一般不使用memcpy而是使用memmove,就好比我们考试只需考60分,90分就要其他人去考吧,而我们却发现memcpy连重叠的拷贝也能做到,这就是超预期了,而我们模拟出来的函数只是具备了拷贝不重叠的内存拷贝功能,vs的库函数memcpy两者具备,但是在一些编译器里就会不一定两种功能都有。
memove
从这里可以看出memmove函数的参数和memcpy是一样的,所以memove函数具备了memcpy的所有功能
#include<stdio.h> #include<string.h> #include<ctype.h> #include<stdlib.h> #include<assert.h> int main() { int arr[] = { 1,2,3,4,5,6,7,8,9 }; int arr1[10] = { 0 }; memmove(arr1, arr, sizeof(arr[0]) * 9); return 0; }
我们来模拟一下
如果模拟这个函数很容易就会把memcpy的功能加上重叠的功能,重叠的方法很多人就会想到我要重新开辟一块临时空间存放和arr一样的,然后进行一一的拷贝,然后再覆盖原来的arr,这个方法是可行的,但是这样很麻烦,那有没有在一个数组内就可以进行拷贝呢?答案是有的
如上图
如果我们要3-7拷贝到1-5的位置上去,我们可以先把3拷贝到1然后依次往下,就可以解决原来数字被覆盖的问题,
如果我们要把1-5拷贝到5-9的位置我们就先拷贝5到9的位置上去,往后依次往前
#include<stdio.h> void* my_memmove(void* arr1, const void* arr, size_t num) { char* pa1 = arr1; const char* pa = arr; // 后往前拷贝 if (pa1 > pa) { pa1 += num - 1; pa += num - 1; while (num) { *pa1 = *pa; pa1--; pa--; num--; } } else { //前往后拷贝 while (num) { *pa1 = *pa; pa1++; pa++; num--; } } return arr1; } int main() { int arr[] = { 1,2,3,4,5,6,7,8,9 }; int arr1[10] = { 0 }; my_memmove(arr, arr + 2, sizeof(arr[0]) * 5); return 0; }
这里我们要注意一下数组arr的第n个元素的地址是arr+(n - 1)
memset
填充内存块
把从ptr开始的num个字节填充为value
#include<stdio.h> #include<string.h> int main() { char arr[] = "abcdefg"; memset(arr, 't', 5); printf("%s", arr); return 0; }
结果为:
所以我们可以认为memset是以字节为单位的进行设置的,如果不相信,下面为例
#include<stdio.h> #include<string.h> int main() { int arr[10] = { 0 }; memset(arr, 1, 40); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } return 0; }
结果为:
这里就是arr里面 存储的内存,我们的想法是把arr每个元素设置成1,而结果却不对,memset是以字节为单位进行设置的,需要注意一下,在vs是小端存储(高阶数存放在低地址) 结果为01010101
如果我们要模拟实现就是
#include<stdio.h> #include<string.h> void* my_memset(void* ptr, int value, size_t num) { char* pr = ptr; while (num) { *pr = value; pr++; num--; } return ptr; } int main() { char arr[] = "abcdefghij"; int arr1[5] = { 0 }; my_memset(arr, '0', sizeof(arr[0]) * 5); return 0; }
memcmp
比较两个内存块的内容
#include<stdio.h> #include<string.h> int main() { int arr1[] = { 1,2,3,4,5,6,7,8,9 }; // 数组的存储方式:01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 06 00 00 00 07 00 00 00 08 00 00 00 09 00 00 00 int arr[] = { 1,2,3,6 }; // 数组的存储方式:01 00 00 00 02 00 00 00 03 00 00 00 06 00 00 00 printf("%d", memcmp(arr, arr1, 16)); return 0; }
简单的理解,和strcmp的比较方式是一样的,一旦匹配到不相等的内存就会返回
如果不相信还有一个例子
#include<stdio.h> #include<string.h> int main() { int arr1[] = { 1,2,3,4,5,6,7,8,9 }; // 数组的存储方式:01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 06 00 00 00 07 00 00 00 08 00 00 00 09 00 00 00 int arr[] = { 1,2,3,0x11223301}; // 数组的存储方式:01 00 00 00 02 00 00 00 03 00 00 00 01 33 22 11 printf("%d", memcmp(arr, arr1, 16)); return 0; }
我们来模拟一下
#include<stdio.h> #include<string.h> int my_memcmp(const void* ptr1, const void* ptr2, size_t num) { while (num) { if (*((char*)ptr1) == *((char*)ptr2)) { ptr1 = (char*)ptr1 + 1; ptr2 = (char*)ptr2 + 1; } else { return *((char*)ptr1) - *((char*)ptr2); } } return 0; } int main() { int arr[] = { 1,2,3,4,5,6,7,8,9 }; int arr1[] = { 1,2,3,4,5,0x11223306 }; int num = my_memcmp(arr1, arr, 6); printf("%d", num); return 0; }
总结
到这里字符串相关的函数就学习完了,有不懂的可以私聊我