网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事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;
既有适合小白学习的零基础资料,也有适合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++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新