既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
三、动态内存函数的介绍和拓展
🍋malloc()函数
知识点1:
🔑****malloc()函数的头文件:#include <stdlib.h>🔑****malloc()函数的声明:
函数声明的解释:
▶ size_t 表示无符号类型 size:表示申请分配的内存大小,单位为字节▶返回值:申请成功返回该空间起始地址,申请失败返回NULL指针**,因为不知道申请的空间要存放什么类型数据所以返回****void*类型**
🔑malloc()函数的功能介绍
malloc是C语言提供的一个动态内存开辟的函数**,该函数向内存申请一块连续可用的空间,****并返回指向这块空间的指针。**具体情况如下:
▶ 如果开辟成功,则返回一个指向开辟好空间的指针。
▶ 如果开辟失败,则返回一个 NULL 指针。
▶ 如果开辟失败,则返回一个 NULL 指针。
▶ 如果 size 为 0(开辟0个字节),malloc 的行为是标准未定义的,结果将取决于编译器。
🔑注意:
1. malloc返回值有可能是NULL指针,使用前需要检查
2. malloc申请的空间并没有被初始化🔑代码举例说明:
用malloc()来创建一个 数组。可以在程序运行时使用malloc()请求一个存储块,另外还需要一个指针来存放该块在内存中的位置。
int * ptd; ptd = (int * ) malloc (30 * sizeof(int)); if (ptd == NULL) //空间申请失败则退出 { return -1; }
代码解释:
▶****这段代码请求30个 int类型 值的空间,并且把ptd指向该空间所在位置。
▶****注意: ptd是作为指向一个 int类型值 的指针声明
的,而不是
指向30个 int类型 值的数据块的指针。
🍊free()函数
知识点1:
🔑 free()函数的头文件:#include <stdlib.h>🔑 free()函数的声明:
函数声明的解释:
ptr : 指向先前用malloc、calloc或realloc分配的内存块的指针
🔑 free()函数的功能:
释放申请的动态内存分配的空间(即malloc、calloc、realloc函数申请的空间)具体情况:
▶ 如果参数 ptr 指向的空间不是动态开辟的,那么 free 函数的行为是未定义的。
▶ 如果参数 ptr 是 NULL 指针,那么 free 将不会执行任何动作。
🔑注意事项:
▶ 使用完之后一定要记得使用 free 函数释放所开辟的内存空间。▶ 使用指针指向动态开辟的内存,使用完并 free 之后一定要记得将其置为空指针,防止越界访问。
原因:free()函数只会释放ptr指向空间的值,但ptr本身不会被置空。
🔑代码举例:
#include <stdio.h> #include <stdlib.h> int main() { //申请10个int类型大小空间,10 * sizeof(int)相对于sizeof(40)更具有移植性 //由于malloc返回值为void*类型,所以强制类型转换为int*类型 int n; // 开辟空间数 举例为 10 printf("请输入想开辟的 int 数组大小\n"); scanf("%d", &n); int* p = (int*)malloc(n * sizeof(int)); if (p == NULL) { exit(EXIT_FAILURE); //p 现在指向有 n 个元素的数组 } int i = 0; for (i = 0; i < 10; i++) //打印这10个元素 { printf("%d ", *(p + i)); } printf("\n"); for (i = 0; i < 10; i++) //对数组元素赋值 { p[i] = i; // 此时可以将 指针 p 看作数组名 } for (i = 0; i < 10; i++) //打印这10个元素 { printf("%d ", *(p + i)); } printf("\n"); free(p); //释放p所指向动态内存分配的空间 p = NULL;//将p置为NULL指针,防止访问一个已释放的空间 return 0; }
运行结果:
请输入想开辟的 int 数组大小: 10 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 0 1 2 3 4 5 6 7 8 9
代码解释:
▶ 开始 指针 p 指向 int 类型 开辟的40个字节空间,并没有赋值,所以输出的值都是随机的。
▶ exit()函数。该函数的原型在 stdlib.h 中,用来在
内存分配失败时结束程序
。值 EXIT_FAILURE 也在这个头文件中定义。标准库提供了两个保证能够在所有操作系统 下工作的返回值:
EXIT SUCCESS(或者,等同于0)指示程序正常终止;
EXIT_FAILURE指示程序异常终止。
知识点2:内存泄露
大家是否有跟我一样的想法,目前我们知道了动态内存的开辟函数 malloc() ,之后便出现了释放函数 free(),我有点好奇,在我开辟函数之后,我不去释放,你能把我怎样呢?抱着这样的想法,我做了一个实验:
#include<stdio.h> #include<malloc.h> void gobble (double ar[], int n); int main() { double glad[2000]; int i; for(i = 0; i<100000000; i++) { gobble(glad, 2000); } } void gobble(double ar[], int n) { double *temp = (double *) malloc(n*sizeof(double)) ; // free(temp);/*忘记使用*/ //我就皮,我就用 }
代码解释:
▶ 第一次调用gobble()时,它创建了指针temp,并使用malloc()为之分配16000字节 的内存(设double是8个字节)。
假定我们如暗示的那样没有使用free()。
当函数终止时,指针temp作为一个自动变量消失了。
但它所指向的16000个字节的内存仍旧存在。
我们无法访问这些内存,因为地址不见了。
由于没有调用free(),不可以再使用它了。▶****第二次调用gobble(),它又创建了一个temp,再次使用malloc()分配16000个字节 的内存。
第一个16000字节的块已不可用,因此malloc()不得不再找一个l6000字节的块。
当函数终止时,这个内存块也无法访问,不可再利用。▶ 但循环执行了1000次,因此在循环最终结束时,已经有1600万字节的内存从内存池中移 走。事实上,在到达这一步前,程序很可能已经内存溢出了。
**▶这类问题被称为
内存泄漏(memory leak)
****,**可以通过在函数末尾处调用free()
防止该问题出现。
🍌calloc()函数
知识点1:
🔑****calloc()函数的头文件:#include <stdlib.h>🔑****calloc()函数的声明:
🔑****解释函数声明:
▶****num:元素个数▶****size: 元素大小
▶****返回值:申请成功返回该空间起始地址,申请失败返回NULL指针,因为不知道申请的空间要存放什么类型数据所以返回void*类型。
🔑calloc()函数的功能:
calloc函数与malloc函数功能一样,区别主要在于calloc会对分配的空间初始化为0,另外它们请求内存大小的方式不同。🔑验证malloc()函数与calloc()函数的区别:
malloc()函数:#include <stdio.h> #include <stdlib.h> int main() { // malloc int* p = (int*)malloc(40); // 开辟40个空间 if (p == NULL) { exit(EXIT_FAILURE); //p 现在指向有 10 个元素的数组 } int i = 0; for (i = 0; i < 10; i++) printf("%d ", *(p + i)); free(p); p = NULL; return 0; }
运行结果:
// 随机的 10 个值
calloc()函数:
#include <stdio.h> #include <stdlib.h> int main() { // calloc int* p = (int*)calloc(10, sizeof(int)); // 开辟10个大小为int的空间,40 if (p == NULL) { exit(EXIT_FAILURE); //p 现在指向有 10 个元素的数组 } int i = 0; for (i = 0; i < 10; i++) printf("%d ", *(p + i)); free(p); p = NULL; return 0; }
运行结果:
0 0 0 0 0 0 0 0 0 0
🔑****总结:
说明 calloc 会对内存进行初始化,把空间的每个字节初始化为 0 。如果我们对于申请的内存空间的内容,要求其初始化,我们就可以使用 calloc 函数来轻松实现。
🍇realloc()函数
知识点1:
🔑****realloc()函数的头文件:#include <stdio.h>🔑****realloc()函数的声明:
🔑声明的解释:
▶ ptr:指向先前用malloc、calloc或realloc分配的内存块的指针
▶ size:动态内存空间新大小,单位为字节
▶ 返回值:返回调整后空间的起始地址,调整失败返回NULL指针
🔑realloc()函数的功能:
让动态内存管理更加灵活。用于重新调整之前调用 malloc 或 calloc 所分配的ptr 所指向的内存块的大小,可以对动态开辟的内存进行大小的调整。🔑realloc()函数调整内存的 4 中情况:(看图解)
▶ 情况一:在原有的基础上扩大空间原有空间之后有足够大的空间。
▶ 情况二:原有空间之后没有足够大的空间。
原空间之后没有足够多的空间满足扩展需求,在内存上另外寻找一个适合大小的来连续空间来使用,并将原空间数据先复制过来然后释放空间。这样函数返回的是一个新空间的内存地 址
▶ 情况三:缩小原有的空间
原空间尾部的部分空间被释放,剩余空间数据依旧保留。
▶ 情况四:
🔑代码演示:
realloc()调整函数大小:#include <stdio.h> #include <stdlib.h> int main() { int* p = (int*)calloc(10, sizeof(int)); if (p == NULL) { exit(EXIT_FAILURE); //p 现在指向有 10 个元素的数组 } // 使用 int i = 0; for (i = 0; i < 10; i++) { *(p + i) = 5; } // 此时,这里需要p指向的空间更大,需要20个int的空间 // realloc 调整空间 p = (int*)realloc(p, 20 * sizeof(int)); // 调整为20个int的大小的空间 // 释放 free(p); p = NULL; }
❗ 疑问: 刚才提到的第四种情况,如果 realloc 找不到合适的空间,就会返回空指针。我们想让它增容,他却存在返回空指针的危险,这怎么行?
🔑代码优化:
#include <stdio.h> #include <stdlib.h> int main() { int* p = (int*)calloc(10, sizeof(int)); if (p == NULL) { exit(EXIT_FAILURE); //p 现在指向有 n 个元素的数组 } // 使用 int i = 0; for (i = 0; i < 10; i++) { *(p + i) = 5; } // 此时,这里需要 p 指向的空间更大,需要 20 个int的空间 // realloc 调整空间 int* ptmp = (int*)realloc(p, 20*sizeof(int)); // 如果ptmp不等于空指针,再把p交付给它 if (ptmp != NULL) { p = ptmp; } // 释放 free(p); p = NULL; return 0; }
🔑代码演示全过程;
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> int main() { int* p = (int*)malloc(10 * sizeof(int)); if (p == NULL) { exit(EXIT_FAILURE); //p 现在指向有 10 个元素的数组 } int i = 0; for (i = 0; i < 10; i++) //对数组元素赋值 { *(p + i) = i; } int* ptr = (int *)realloc(p, 20 * sizeof(int)); //对动态内存大小进行调整
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
exit(EXIT_FAILURE); //p 现在指向有 10 个元素的数组
}
int i = 0;
for (i = 0; i < 10; i++) //对数组元素赋值
{
(p + i) = i;
}
int ptr = (int *)realloc(p, 20 * sizeof(int)); //对动态内存大小进行调整
[外链图片转存中…(img-kstWt9uo-1715799837481)]
[外链图片转存中…(img-e1zToiUV-1715799837481)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!