四、内存操作函数
1.memcpy函数
函数原型:void *memcpy( void *dest, const void *src, size_t count );
头 文 件:<memory.h>or<string.h>
函数功能:内存拷贝:(适用于内存不重叠的场景)
功能:
1.函数memcpy从src的位置开始向后复制count个字节的数据到dest的内存位置;
2.这个函数在遇到 \0 的时候并不会停下来;
3.如果source和destination有任何重叠,复制的结果都是未定义的;
举例:
#include <stdio.h> #include <string.h> int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 }; memcpy(arr1, arr1 + 4, 16); //arr1+2是指向5的,从这个位置向后16个字节的数据存到arr1向后16个字节 //也就是把5 6 7 8 拷贝到1 2 3 4 上去 for (int i = 0; i < 10; i++) { printf("%d ", arr1[i]); } printf("\n"); return 0; }
2.memmove 函数
函数原型:void *memmove( void *dest, const void *src, size_t count );
头 文 件:<string.h>
函数功能:内存拷贝:(适用于内存重叠或不重叠的场景)
注意事项:
1.和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
2.如果源空间和目标空间出现重叠,就得使用memmove函数处理
举例:
#include <stdio.h> #include <string.h> int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 }; memmove(arr1, arr1 + 2, 16); //arr1+2是指向3的,从这个位置向后16个字节的数据存到arr1向后16个字节 //也就是把3 4 5 6 拷贝到1 2 3 4 上去(这里就是内存重叠了,重叠的位置是3 4) for (int i = 0; i < 10; i++) { printf("%d ", arr1[i]); } printf("\n"); return 0; }
3.memcmp函数
函数原型:int memcmp( const void *buf1, const void *buf2, size_t count );
头 文 件:<memory.h>or<string.h>
函数功能:内存比较:(比较buf1和buf2指针开始的num个字节)
比较方法:
1.当buf1<buf2时 返回<0
2.当buf1=buf2时 返回=0
3.当buf1>buf2时 返回>0
举例:
#include <stdio.h> #include <string.h> int main() { int arr1[] = { 1,2,3,4,5 }; int arr2[] = { 1,2,3,6,6 }; int ret = memcmp(arr1, arr2, 12); //这里向后比较12个字节,就是比较1 2 3 if (ret > 0) { printf("ret=%d arr1>arr2\n", ret); } else if (ret < 0) { printf("ret=%d arr1<arr2\n", ret); } else { printf("ret=%d arr1=arr2\n", ret); } return 0; }
4.memset函数
函数原型:void *memset( void *dest, int c, size_t count );
头 文 件:<memory.h>or<string.h>
函数功能:内存设置(memset函数将dest的第一个count个字节设置为字符c)
举例:
#include <stdio.h> #include <string.h> int main() { char str[] = "almost every programmer should know memset!"; memset(str, '-', 6);//从起始位置开始向后6个字节的内容改为 '-' puts(str); return 0; }.
五、库函数的模拟实现
1.模拟实现strlen函数
①递归实现
#include <stdio.h> int my_strlen(const char* pa) { if (*pa != '\0') { return 1 + my_strlen(pa + 1);//1+1+1+1+1+1+0 } else { return 0; } } int main() { char arr[] = "abcdef"; int ret = my_strlen(arr); printf("arr的长度为:%d\n", ret); return 0; }
②计数器实现
#include <stdio.h> int my_strlen(const char* pa) { int count = 0; for (int i = 0; pa[i] != '\0'; i++) { count++;//只要不等于 \0 就加一 } return count; } int main() { char arr[] = "abcdef"; int ret = my_strlen(arr); printf("arr的长度为:%d\n", ret); return 0; }
③指针 - 指针
#include <stdio.h> int my_strlen(const char* pa) { char* pa1 = pa;//先保存首元素的地址 while (*pa1) { pa1++;//去找 \0 的地址 } return pa1 - pa;//pa1是 \0 的地址,pa是首元素的地址;相减就得到元素个数 } int main() { char arr[] = "abcdef"; int ret = my_strlen(arr); printf("arr的长度为:%d\n", ret); return 0; }
2.模拟实现strcpy函数
#include <stdio.h> #include <assert.h> char* my_strcpy(char* dest, const char* src) { assert(dest && src);//断言 --- 判断这两个指针是否为空 char* ret = dest; while (*dest++ = *src++)//直接赋值,直到遇到'\0'就停下 { ; } return ret; } int main() { char arr1[20] = "xxxxxx"; char arr2[] = "Hello"; printf("拷贝前为:%s\n", arr1); char* ret = my_strcpy(arr1, arr2); printf("拷贝后为:%s\n", ret); return 0; }
#include <stdio.h> #include <assert.h> char* my_strcpy(char* dest, const char* src) { assert(dest && src);//断言 --- 判断这两个指针是否为空 int i = 0; for (i = 0; src[i] != '\0'; i++) { dest[i] = src[i];//赋值,但是没有'\0'结束标志 } dest[i] = '\0';//末尾添加一个'\0' } int main() { char arr1[20] = "xxxxxx"; char arr2[] = "Hello"; printf("拷贝前为:%s\n", arr1); my_strcpy(arr1, arr2); printf("拷贝后为:%s\n", arr1); return 0; }
3.模拟实现strcat函数
#include <stdio.h> #include <assert.h> char* my_strcat(char* dest, const char* src) { assert(dest && src);//断言 --- 判断这两个指针是否为空 while (*dest) { //先找到dest所指向的数组中'\0'的位置 dest++; } while (*src) { *dest++ = *src++;//进行追加 } } int main() { char arr1[20] = "Hello "; char arr2[] = "World"; printf("追加前为:%s\n", arr1); my_strcat(arr1, arr2); printf("追加后为:%s\n", arr1); return 0; }
4.模拟实现strcmp函数
#include <stdio.h> #include <assert.h> int my_strcmp(char* str1, const char* str2) { assert(str1 && str2);//断言 --- 判断这两个指针是否为空 while (*str1==*str2) { if (*str1 == '\0') { return 0; } str1++; str2++; } return *str1 - *str2; } int main() { char arr1[] = "ABCDEF"; char arr2[] = "ABCDE"; int ret = my_strcmp(arr1, arr2); if (ret > 0) { printf("ret = %d:arr1>arr2", ret); } else if (ret < 0) { printf("ret = %d:arr1<arr2", ret); } else { printf("ret = %d:arr1=arr2", ret); } return 0; }
5.模拟实现strncpy函数
#include <stdio.h> #include <assert.h> char* my_strncpy(char *dest, const char *src,size_t count) { assert(dest && src); char *ret = dest; //1.拷贝字符串的个数 while (count && (*dest++ = *src++)) { count--; } //2.不够的用\0补 if (count) { while (--count) { *dest++ = '\0'; } } return ret; } int main() { char arr1[20] = "xxxxxxxx"; char arr2[] = "Hello World"; printf("拷贝前为:%s\n", arr1); char* ret = my_strncpy(arr1, arr2, 5); printf("拷贝后为:%s\n", ret); return 0; }
6.模拟实现strncat函数
#include <stdio.h> #include <assert.h> char* my_strncat(char *dest, const char *src, int count) { assert(dest && src); char *ret = dest; //1.先找到\0的位置 while (*dest++) { ; } dest--; //2.将源字符串追加进去(根据指定的个数) while (count--) { //3.只要不是\0就一直追加,追加到\0为止 if (!(*dest++ = *src++)) { return ret; } } *dest = '\0'; return ret; } int main() { char arr1[20] = "Hello "; char arr2[] = "World"; printf("追加前的字符串为:%s\n", arr1); char *ret = my_strncat(arr1, arr2, 8); printf("追加后的字符串为:%s\n", ret); return 0; }
7.模拟实现strncmp函数
#include <stdio.h> #include <assert.h> int my_strncmp(char *str1, const char *str2, int count) { assert(str1 && str2); while(count&&(*str1 == *str2)) { if (*str1 == '\0') return 0; str1++; str2++; count--; } return *str1 - *str2; } int main() { char arr1[] = "Hello"; char arr2[] = "Helld"; int ret = my_strncmp(arr1, arr2, 5); if (ret > 0) { printf("ret = %d:arr1>arr2", ret); } else if (ret < 0) { printf("ret = %d:arr1<arr2", ret); } else { printf("ret = %d:arr1=arr2", ret); } return 0; }
8.模拟实现strstr函数
#include <stdio.h> #include <assert.h> char* my_strstr(char* str1, const char* str2) { assert(str1 && str2); char* s1; char* s2; char* cp = str1; //如果传过来的是 \0 if (*str2 == '\0') { return str1; } //两种情况: // arr1-- abcdef arr1-- abbbcdef // 查找 arr2-- bcd arr2-- bbc while (*cp) { s1 = cp; s2 = str2; while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2) { s1++; s2++; } if (*s2 == '\0') { return cp; } cp++; } return NULL;//没有找到的情况 } int main() { char arr1[] = "abbbcdef"; char arr2[] = "bcd"; char* ret = my_strstr(arr1, arr2); if (ret == NULL) { printf("找不到\n"); } else { printf("找到了,是:%s\n", ret); } return 0; }
9.模拟实现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;//强制转换为char*,是为了让其一次访问一个字节的内容 dest = (char*)dest + 1; src = (char*)src + 1; } return ret; } int main() { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; my_memcpy(arr, arr + 4, 4 * sizeof(int)); for (int i = 0; i < 10; i++) { printf("%d ", arr[i]); } return 0; }
10.模拟实现memmove函数
#include <stdio.h> #include <assert.h> void* my_memmove(void* dest, const void* src, size_t count) { assert(dest && src); void* ret = dest; if (dest < src) { //从前向后拷贝 while (count--) { //强制转换为char*,是为了让其一次访问一个字节的内容 *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } } else { //从后向前拷贝 while (count--) { *((char*)dest + count) = *((char*)src + count); } } return ret; } int main() { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; my_memmove(arr, arr + 2, 4 * sizeof(int)); for (int i = 0; i < 10; i++) { printf("%d ", arr[i]); } return 0; }
11.模拟实现memcmp函数
#include <stdio.h> #include <assert.h> int my_memcmp(const void* ptr1, const void* ptr2, size_t num) { assert(ptr1 && ptr2); //void* --- 无具体类型指针 //1.可以接受任意类型的指针 //2.但不能进行运算 //这里进行强制转换后就能够执行了 while (num&&(*(char*)ptr1== *(char*)ptr2)) { if (*(char*)ptr1 == '\0') { return 0; } ptr1 = (char*)ptr1+1; ptr2 = (char*)ptr2+1; num--; } return *(char*)ptr1 - *(char*)ptr2; } int main() { char buf1[] = "ABCDEF"; char buf2[] = "ABCDGS"; int ret = my_memcmp(buf1, buf2, 4 * sizeof(char)); if (ret > 0) { printf("buf1>buf2\n"); } else if (ret < 0) { printf("buf1\<buf2\n"); } else { printf("buf1=buf2\n"); } return 0; }
12.模拟实现memset函数
#include <stdio.h> #include <assert.h> void* my_memset(void* ptr, int val, size_t num) { assert(ptr); for (int i = 0; i < num; i++) { *((char*)ptr + i) = val; } return ptr; } int main() { char str[] = "almost every programmer should know memset!"; char ch = '-'; my_memset(str, ch, 6); puts(str); return 0; }
六、总结
以上的这些库函数大部分使用较多,深入了解并牢牢掌握其功能,对于这方面的解题会得心应手,笔者可能在模拟实现上不一定是最优解,但是可以帮助大家从了解到掌握。