【C语言进阶】常见的字符串函数和内存函数详解及模拟实现_c语言 返回常量字符串

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

char arr2[] = "YES";
strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;

}


**🚀 运行结果:**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/089b7703f47b49a084c2c439c8323ec3.png)  
 从监视中,可以看到:strcat将源字符串(包括\0),追加至目标字符串的结尾并覆盖掉目标空间的\0  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/bced50bc715e4934ba6e7a2c24dc18b6.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aSn54yp54yp77yB,size_20,color_FFFFFF,t_70,g_se,x_16)


**📌注意事项:**  
 ①源字符串必须以\0结尾  
 ②源字符串不能追加给自己  
 ③目标空间必须足够大,以确保能够存放源字符串 src  
 ④目标空间必须可变,即目标空间 src 不可以被 const 修饰


1️⃣源字符串必须以\0结尾  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/d7dcbbf9339f4214aebe490005df8c5d.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aSn54yp54yp77yB,size_20,color_FFFFFF,t_70,g_se,x_16)


分析:源字符串不以\0结尾,导致非法访问


2️⃣源字符串不能追加给自己  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/4f485662129a48ceaf7a02c00d14bd02.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aSn54yp54yp77yB,size_20,color_FFFFFF,t_70,g_se,x_16)  
 监视:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/566ba07a039145a593169293091d8827.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aSn54yp54yp77yB,size_20,color_FFFFFF,t_70,g_se,x_16)  
 可以看出strcat在疯狂地呐喊这"CSDN!",直到断气!  
 emmm正经点,就是strcat会一直往arr1追加"CSDN!",直到越界非法访问。


老规矩,我们用图来解释:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/53ad4ccbc18b4c3a8e34ee6fb3f1f6a8.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aSn54yp54yp77yB,size_20,color_FFFFFF,t_70,g_se,x_16)  
 arr1给自己追加字符串时,会将字符串中的\0覆盖掉(第一个!后的\0被覆盖),导致没有\0追加上去,造成死循环直到越界非法访问。![请添加图片描述](https://img-blog.csdnimg.cn/6fe0d3985f25403d8bcd332135cd1ed1.gif)




---


**⚡模拟实现strcat()函数:**



char* my_strcat(char* dest, const char* src)
{
assert(src && dest);
char* begin = dest;//记录目标字符串的起始地址
//找到dest中的\0
while (*dest)
{
dest++;
}
//到此,dest指向\0,开始追加
while (*dest++ = *src++)
{
;
}
return begin;
}
int main()
{
char arr1[20] = “CSDN!”;
char arr2[] = “YES”;
my_strcat(arr1, arr2);
printf(“%s\n”, arr1);
return 0;
}


**🚀 运行结果:**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/6f0eed9221074a5894cdec21a88cf2d7.png)




---


### 3.strcmp()


头文件:<string.h>



int strcmp(const char* str1, const char* str2);//字符串比较函数


说明:两个字符串自左向右逐个字符相比(按 ASCII 值大小相比较),从第一对字符比起,若相等则比较下一对,直到遇到不同的字符或 \0 才停止  
 参数:


* str1:要进行比较的第一个字符串
* str2:要进行比较的第二个字符串


返回值:


* str1 小于 str2,返回负数
* str1 大于 str2,返回整数
* str1 等于 str2,返回 0


**💬代码演示:**



int main()
{
char* p1 = “abcd”;
char* p2 = “abxy”;
printf(“%d\n”, strcmp(p1, p2));
return 0;
}


**🚀 运行结果:**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/d3ce0daf2b3c4bcbbe649853336e7c7e.png)  
 **🔍分析:** 比较c和x,c(ASCII) < x(ASCII),返回负数-1




---


📌注意事项:  
 ①str1和str2都要以 \0 作为字符串的结尾,否则会造成越界非法访问。  
 ②根据编译器的不同,返回的结果也不同。在 VS2019 中,大于返回 1,等于返回 0,小于返回 -1。但在 Linux-gcc 中,大于返回正数,等于返回0,小于返回负数。  
 因此有下面建议:



// 不推荐 ❌
if(strcmp(p1, p2) == 1)
printf(“p1 > p2”);
else if(strcmp(p1, p2 == 0))
printf(“p1 == p2”);
else if(strcmp(p1, p2) == -1)
printf(“p1 < p2”);
// 推荐 ✅
if(strcmp(p1, p2) > 0)
printf(“p1 > p2”);
else if(strcmp(p1, p2 == 0))
printf(“p1 == p2”);
else if(strcmp(p1, p2) < -1)
printf(“p1 < p2”);




---


**⚡ 模拟实现strcmp()函数:**



int my_strcmp(const char* str1, const char* str2)//仅比较不修改,都用const
{
assert(str1 && str2);//防止访问空指针
while (*str1 == *str2)
{
if (*str1 == ‘\0’)//遇 \0 则停止
return 0;
str1++;
str2++;
}
return *str1 - *str2;
}




---


## 三、长度受限制的字符串函数


### 1.strncpy()


头文件:<string.h>



char* strncpy(char* dest, const char* src, size_t n);//指定长度的字符串拷贝函数


说明:strncpy函数把 src 所指向的字符串复制到 dest,最多复制 n 个字符(遇到中间的\0停止,会小于n)。


📌注意事项:  
 ①当 src 的长度小于 n 时,dest 的剩余部分将用 \0 填充。  
 ②目标空间必须足够大,以确保能够存放源字符串 src。  
 ③目标空间必须可变,即目标空间 src 不可以被 const 修饰。


1️⃣当 src 的长度小于 n 时,dest 的剩余部分将用 \0 填充。



int main()
{
char arr1[10] = “abcde”;
char arr2[] = “xyz”;
strncpy(arr1, arr2, 5);//3 < 5
printf(“%s\n”, arr1);
return 0;
}


![在这里插入图片描述](https://img-blog.csdnimg.cn/1712ac0493704c7dbb906daaaeebfc3b.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aSn54yp54yp77yB,size_20,color_FFFFFF,t_70,g_se,x_16)  
 2️⃣3️⃣略(上面已讲)




---


**⚡模拟实现strncpy()函数:**



char* my_strncpy(char* dest, const char* src, size_t n)
{
assert(dest && src);
char* begin = dest;
while (n && (*dest = *src))
{
dest++;
src++;
n–;
}
while (n–)
{
*dest = ‘\0’;
}
return begin;
}
int main()
{
char arr1[10] = “abcde”;
char arr2[] = “xyz”;
my_strncpy(arr1, arr2, 5);//3 < 5
printf(“%s\n”, arr1);
return 0;
}


**🚀 运行结果:**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/ae95af2d05c9448baa7a8e3453c79ca0.png)




---


### 2.strncat()


头文件:<string.h>



char* strncat(char* dest, const char* src, size_t n);//指定长度的字符串追加函数


说明:源字符串最多追加n个字符到目标空间。  
 **💬代码演示:**



int main()
{
char arr1[] = “CSDN!\0xxxx”;
char arr2[] = “YES”;
strncat(arr1, arr2, 5);
printf(“%s\n”, arr1);
return 0;
}


①n大于源字符串,追加至源字符串的 \0 停止追加;  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/a8c65f38a3ac4563958ee96a2d6d89de.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aSn54yp54yp77yB,size_20,color_FFFFFF,t_70,g_se,x_16)


②n小于源字符串,追加完主动补 \0。



int main()
{
char arr1[] = “CSDN!\0xxxx”;
char arr2[] = “YES”;
strncat(arr1, arr2, 1);
printf(“%s\n”, arr1);
return 0;
}


![在这里插入图片描述](https://img-blog.csdnimg.cn/3a2acf2840ec4612b81a76864a7e3585.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aSn54yp54yp77yB,size_20,color_FFFFFF,t_70,g_se,x_16)  
 **📌注意事项:** 与strcat不同的是:字符串可通过strncat给自己追加,因为追加完会补 \0




---


**⚡模拟实现strncat()函数:**



char* my_strncat(char* dest, const char* src, size_t n)
{
assert(dest && src);
char* begin = dest;
//找出dest的 \0
while (*dest)
dest++;
//追加
while (n && (*dest++ = *src++))
n–;
//n小于源字符串补0
if (n == 0)
*dest = ‘\0’;
return begin;
}




---


### 3.strncmp()


头文件:<string.h>



int strncmp(const char* str1, const char* str2, size_t n);//指定长度的字符串比较函数


说明:把 str1 和 str2 进行比较(按 ASCII 值大小),最多比较前 n 个字符。


**💬 代码演示:**



int main()
{
char* p1 = “abcde”;
char* p2 = “abxyz”;
printf(“%d\n”, strncmp(p1, p2, 3));
return 0;
}


**🚀运行结果:**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/deea9bded263482c96eefda1b39bffaa.png)




---


**⚡ 模拟实现strncmp()函数:**



int my_strncmp(const char* str1, const char* str2, size_t n)
{
assert(str1 && str2);
while (n-- && (*str1 == *str2))
{
str1++;
str2++;
}
return *str1 - *str2;
}




---


## 四、字符串查找函数


### 1.strstr()


头文件:<string.h>



char* strstr(const char* string, const char* substring);//字符串查找子串函数


说明:字符串 string 中查找第一次出现字符串 substring 的位置,不包含终止符 ‘\0’。该函数返回在 string 中第一次出现 substring 字符串的位置,若未找到则返回 NULL。




---


**⚡ 模拟实现strstr()函数:**



char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
if (*str2 == ‘\0’)
{
return NULL;//子串为空,返回NULL
}
char* s1;
char* s2;
char* cp = str1;
while (*cp != ‘\0’)
{
s1 = cp;
s2 = str2;
while (*s1 == *s2 && *s1 != ‘\0’ && *s2 != ‘\0’)
{
s1++;
s2++;
}
if (*s2 == ‘\0’)
{
return cp;
}
cp++;
}
return NULL;
}



> 
> **📚拓展:**  
>  KMP算法 - 在字符串中查找子字符串的一种算法
> 
> 
> 




---


### 2.strtok()


头文件:<string.h>



char* strtok(char* str, const char* delim);//分割字符串函数


说明:将字符串 str 分解为一组字符串,delim 为分隔符集合。  
 原理:找到分隔符,并用 ‘\0’ 代替,即字符串的结束符。  
 参数:


* str:一个或多个分隔符和标记组成的字符串。
* delim:包含分隔符的 C 字符串。



> 
> 解释分隔符和标记:  
>  `. | - @`等等称为分隔符;  
>  对于www`.`csdn`.`net,由分隔符 `.` 所分割出来的子字符串被称为标记,如www,csdn,net
> 
> 
> 


返回值:从 str 开头开始的一个个被分割的串的指针,当没有被分割的串时则返回NULL。




---


**📌注意事项:**  
 ①这是调用一次strtok的结果:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/6767b614fcf0426bb57ed1e920d01feb.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aSn54yp54yp77yB,size_20,color_FFFFFF,t_70,g_se,x_16)  
 ②想要完整分割字符串,则要配合循环使用。因为stryok函数会自己保存指针,所以在下一次调用时,只需要给它传一个NULL即可。  
 ③strtok函数会修改源字符串。我们一般会对源字符串拷贝一份,并让拷贝出来的去被切割(让替罪羊去送死)。![在这里插入图片描述](https://img-blog.csdnimg.cn/9afa5cd13ebf4ebb8e0f18d79aa57932.png)




---


**💬 正确使用:**



int main()
{
char web[] = “www.csdn.com”;
char* delim = “.@”;//分隔符集合
for (char* p = strtok(web, delim); p != NULL; p = strtok(NULL, delim))
{
printf(“%s\n”, p);
}

//证明源字符串被修改
for (int i = 0; i < sizeof(web)/sizeof(web[0]); i++)
{
	printf("%c", web[i]);
}
return 0;

}


**🚀运行结果:**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/7b5d7f3294404d88b8c22e285e0edce3.png)




---


### 3.strerror()


头文件:<string.h>



char* strerror(int errnum);//字符串报错函数


说明: 从内部数组中搜索错误号 errnum,返回一个指向错误消息字符串的指针。strerror 生成的错误字符串取决于开发平台和编译器。  
 参数:errnum – 错误号,通常是errno  
 使用:errno是一个全局的错误码变量,当C语言的库函数在执行过程中发生错误,就会把对于的错误码赋值到errno中,通过调用strerror函数就可以把错误信息打印出来。




---


**📌注意事项:** 使用errno需要呼叫头文件<errno.h>



#include <string.h>
#include <stdio.h>
#include <errno.h>
int main()
{
printf(“%s\n”, strerror(errno));
printf(“%s\n”, strerror(1));
printf(“%s\n”, strerror(2));
printf(“%s\n”, strerror(3));
return 0;
}


**🚀运行结果:**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/c83741e291044a0da8356ba4b861b0fd.png)


常使用的场景在文件操作(后面会学习,关注我不迷路~😏)



#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));
else
printf(“open file successfully”);
fclose(pf);//关闭文件
pf = NULL;
return 0;
}




---


### 4.perror()


头文件:<stdio.h>



void perror(const char* str);//输出报错信息函数


说明:perror()用来将上一个函数发生错误的原因输出到标准设备 (stderr) 。首先输出字符串 str,后跟一个冒号,然后是一个空格。


联系:此错误原因依照全局变量 error 的值来决定要输出的字符串,perror函数只是将你输入的一些信息和现在的error所对应的错误一起输出。


**💬 代码演示:**



#include<stdio.h>
#include<string.h>
//不需要#include<errno.h>
int main()
{
FILE* pf = fopen(“test.txt”, “r”);
if (pf == NULL)
perror(“fopen”);
else
printf(“open file successfully”);
fclose(pf);//关闭文件
pf = NULL;
return 0;
}


**🔱总结:** 在C语言编程中,通常使用perror()来输出错误信息,用strerror(errno)来获取错误信息。error是错误码,不同的错误码对应这不同的错误信息。




---


## 五、字符函数


### 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 | 任何可打印字符,包括图像字符和空白字符 |


**💬isupper使用:**



#include <stdio.h>
#include <ctype.h>
int main()
{
char ch1 = ‘A’;
int ret = isupper(ch1); // 判断ch1是否为大写
printf(“%d\n”, ret);//1
return 0;
}




---


### 2.字符转换函数


字符转换函数




| 函数 | 功能 |
| --- | --- |
| tolower | 大写转小写 |
| toupper | 小写转大写 |


**💬tolower函数使用:**



#include <stdio.h>
#include <ctype.h>
int main()
{
char ch = tolower(‘H’); // 大写转小写
putchar(ch);//h
return 0;
}




---


## 六、内存操作函数


### 1.memcpy()


头文件:<string.h>



void* memcpy(void* str1, const void* str2, size_t n);//内存拷贝函数


说明:从源存储区 str2 复制 n 个字节到目标存储区 str1,并返回一个指向目标存储区 str1 的指针。


**💬代码演示:**



// 将字符串复制到数组 dest 中
int main()
{
const char src[50] = “www.casdn.net”;
char dest[50];

memcpy(dest, src, strlen(src) + 1);
printf("dest = %s\n", dest);

return(0);

}




---


**📌注意事项:**  
 ①memcpy函数的参数1,参数2都是void\* 型,void\*又称通用类型。  
 ②与strcpy函数不同,memcpy函数遇到 ‘\0’ 不会停止。  
 ③若源空间和目标空间有重叠,则拷贝时会覆盖源字符串内容。


1️⃣memcpy函数的参数1,参数2都是void\* 型,void\*又称通用类型。  
 用结构体类型来测试



struct Stu
{
char name[20];
int age;
};

int main()
{
struct Stu arr1[5] = { 0 };
struct Stu arr2[] = { {“zhangsan”, 69}, {“lisi”, 18} };

memcpy(arr1, arr2, sizeof(arr2));
printf("name:%s\nage:%d\n", arr1[0].name, arr1[0].age);
return 0;

}


**🚀运行结果:**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/6fa01c1701a54207bafd122c02d705ea.png)  
 2️⃣与strcpy函数不同,memcpy函数遇到 ‘\0’ 不会停止。



int main()
{
char arr1[10] = { 0 };
char arr2[] = “abc\0def”;

memcpy(arr1, arr2, 6);
return 0;

}


![在这里插入图片描述](https://img-blog.csdnimg.cn/6bdd6267815e4a568e5c02552b2243b5.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aSn54yp54yp77yB,size_20,color_FFFFFF,t_70,g_se,x_16)  
 memcpy没有停止标志,它会一个个字节搬运。![在这里插入图片描述](https://img-blog.csdnimg.cn/6e82fc49867241eb83daa5a84da1c7d4.png)


3️⃣若源空间和目标空间有重叠,则拷贝时会覆盖源字符串内容。



int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
memcpy(arr + 2, arr, 5 * sizeof(int));
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}


**🚀运行结果:**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/aede9d6e988249d6b412eeeae0b30a3d.png)  
 我们画图分析:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/69a25579a8cd4798ba0f4ca2f58ab36d.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aSn54yp54yp77yB,size_20,color_FFFFFF,t_70,g_se,x_16)  
 我们看到的结果是编译器对memcpy函数优化后的结果。且C标准并不要求memcpy完成发生内存重叠的内容拷贝,但编译器也可能对其进行优化。对内存重叠的内容进行拷贝时,可以使用memmove函数。




---


**⚡ 模拟实现memcpy函数:**



void* my_memcpy(void* dest, const void* src, size_t n)
{
void* begin = dest;
while (n–)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return begin;
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
my_memcpy(arr + 2, arr, 5 * sizeof(int));
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}


**🚀运行结果:**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/30f490fd9ce248ff948f8ebd6f8330c1.png)  
 运行结果也验证了上图中memcpy函数实际上的结果。




---


### 2.memmove()


头文件:<string.h>



void* memmove(void* str1, const void* str2, size_t n);//内存移动函数


说明:将 str2 源区域的前 n 个字节拷贝到 str1 目标区域中。  
 如果目标区域和源区域有重叠的话,memmove() 能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,但复制后源区域的内容会被更改。


**📌注意事项:**  
 ①与memcpy() 不同, memmove() 函数处理的源区域和目标区域是可以重叠的。


C语言标准要求:memcpy() 用来处理不重叠的内存拷贝,而 memmove() 用来处理重叠内存的拷贝。


我就纳闷了,memmove() 既可以拷贝不重叠的数据,又可以拷贝重叠的数据,那我要你memcpy() 有何用?![在这里插入图片描述](https://img-blog.csdnimg.cn/099bdb1d2301478a87a9806ff3191424.png)  
 **💬代码演示:**



int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
memmove(arr + 2, arr, 20);
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}


**🚀运行结果:**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/eef43cd577df4d00ae9fbc237a1e8c9d.png)




---


**⚡模拟实现memmove()函数:**  
 1.首先要清楚,memmove()函数要在memcpy()函数的基础上考虑数据重叠的情况。  
 2.那数据重叠是有几种呢?该如何保护源串在覆盖之前不被修改?


我们用图说话:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/9e5b44fc943f4b548dba535333d24c30.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aSn54yp54yp77yB,size_20,color_FFFFFF,t_70,g_se,x_16)  
 画图后,思路就清晰很多了。



void* my_memmove(void* dest, const* src, size_t n)
{
assert(dest && src);
char* begin = dest;

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

nt arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
memmove(arr + 2, arr, 20);
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}


**🚀运行结果:**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/eef43cd577df4d00ae9fbc237a1e8c9d.png)




---


**⚡模拟实现memmove()函数:**  
 1.首先要清楚,memmove()函数要在memcpy()函数的基础上考虑数据重叠的情况。  
 2.那数据重叠是有几种呢?该如何保护源串在覆盖之前不被修改?


我们用图说话:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/9e5b44fc943f4b548dba535333d24c30.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aSn54yp54yp77yB,size_20,color_FFFFFF,t_70,g_se,x_16)  
 画图后,思路就清晰很多了。



void* my_memmove(void* dest, const* src, size_t n)
{
assert(dest && src);
char* begin = dest;

[外链图片转存中…(img-AVcOwLr3-1715852813536)]
[外链图片转存中…(img-TGFsiPbX-1715852813536)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值