笔记|动态内存管理(续)+柔性数组

目录

1.几道笔试题
1.1题目一:
1.2题目二
1.3题目三
1.4第四题
2.动态内存管理复习
3.柔性数组
3.1柔性数组的特点
3.2柔性数组的使用
3.3柔性数组的优点

1.几道笔试题 1.1题目一:

#include #include #include void GetMemory(char* p) { p = (char*)malloc(100); } void Test(void) { char* str = NULL; GetMemory(str); strcpy(str, "hello world"); printf(str); } int main() { Test(); return 0; }

运行结果
笔记|动态内存管理(续)+柔性数组
文章图片

由于p为形参,开辟完空间出了GetMemory函数就会被销毁,此时没有指针能找到开辟空间的地址,造成内存泄漏问题,因此str还是NULL,而strcpy实现时需要将str进行解引用操作(对NULL解引用)会出问题(非法访问内存),程序崩溃。
strcpy的实现可以参考C语言之字符串+内存函数_臻白林子的博客-CSDN博客_c语言字符串内置函数
注意:这里的printf(str)写法本身是没有问题的,只是由于上面的原因导致无法打印。
举个例子:printf("abc")实际是把首元素a的地址传给printf函数,char *str="abc",str存的是“abc”首元素的地址,相当于数组名,所以printf(str)是合理的。
改法一
#include #include #include void GetMemory(char** p) { *p = (char*)malloc(100); } void Test(void) { char* str = NULL; GetMemory(&str); strcpy(str, "hello world"); printf(str); free(str); str = NULL; } int main() { Test(); return 0; }

运行截图
笔记|动态内存管理(续)+柔性数组
文章图片

改法二

#include #include #include char* GetMemory(char* p) { *p = (char*)malloc(100); return p; } void Test(void) { char* str = NULL; GetMemory(str); strcpy(str, "hello world"); printf(str); free(str); str = NULL; } int main() { Test(); return 0; }

1.2题目二
#include #include #include char* GetMemory(void) { char p[] = "hello world"; //这块空间是在栈区开辟的,出函数后空间自动销毁 return p; } void Test(void) { char* str = NULL; str = GetMemory(); printf(str); } int main() { Test(); return 0; }

当出了GetMemory函数后,“helloworld”这块空间已被释放,p已经没有使用权限了,是个野指针,当再次访问这块空间时,这块空间可能已经被覆盖了(非法访问空间)
举个例子:比如李华工作累了,不想回家休息,在外边找了个酒店住,房间是509,由于太累了,睡了一会,正巧李华的外国朋友John明天要到当地游玩,想找个地方住,就打电话给李华,李华:行,你明天过来住吧,我在509,第二天起床,李华就把房间给退了,john听到昨天李华说可以住509,就直接拖着行李过来酒店说:我就要住509,但是房间已经有人入住了.........
笔记|动态内存管理(续)+柔性数组
文章图片

改法:static修饰
#include #include #include char* GetMemory(void) { static char p[] = "hello world"; //静态区 return p; } void Test(void) { char* str = NULL; str = GetMemory(); printf(str); } int main() { Test(); return 0; }

1.3题目三
#include #include #include void GetMemory(char** p, int num) { *p = (char*)malloc(num); } void Test(void) { char* str = NULL; GetMemory(&str, 100); strcpy(str, "hello"); printf(str); } int main() { Test(); return 0; }

动态开辟的空间用完后要用free释放 ,并把指针置空
改法
#include #include #include void GetMemory(char** p, int num) { *p = (char*)malloc(num); } void Test(void) { char* str = NULL; GetMemory(&str, 100); strcpy(str, "hello"); printf(str); free(str); str=NULL; } int main() { Test(); return 0; }

1.4第四题
#include #include #include void Test(void) { char* str = (char*)malloc(100); strcpy(str, "hello"); free(str); //hello所在的空间已经还给操作系统,此时str为野指针 //free之后,一定要将指针置空 if (str != NULL) { strcpy(str, "world"); //world会把hello覆盖,(非法访问) printf(str); } } int main() { Test(); return 0; }

运行截图
笔记|动态内存管理(续)+柔性数组
文章图片

改法
#include #include #include void Test(void) { char* str = (char*)malloc(100); strcpy(str, "hello"); free(str); str=NULL; if (str != NULL) { strcpy(str, "world"); printf(str); } } int main() { Test(); return 0; }


2.动态内存管理复习 c语言之动态内存管理_臻白林子的博客-CSDN博客
3.柔性数组
结构体中的最后一个元素允许是未知大小的数组,称为柔性数组成员
例如:
struct s1 { int age; char name[20]; int arr[]; //柔性数组成员 };

有些编译器下会报错,可以试试下面这种写法。
struct s2 { int age; char name[20]; int arr[0]; //柔性数组成员,这里的0代表未知大小 };

3.1柔性数组的特点
  1. 结构中的柔性数组成员前面必须至少一个其他成员。否则结构体大小为0
  2. sizeof 返回的这种结构大小不包括柔性数组的内存。
  3. 包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
eg:
#include struct s2 { int age; //4 char name[20]; //20 int arr[0]; //0 }; int main() { printf("%d\n", sizeof(struct s2)); return 0; }

笔记|动态内存管理(续)+柔性数组
文章图片

3.2柔性数组的使用
#include #include struct s3//4 { int num; int arr[]; }; int main() { struct s3* ps = (struct s3*)malloc(sizeof(struct s3) + 40); //假设我们希望数组中有10个元素 ps->num = 100; int i = 0; //使用 for (i = 0; i < 10; i++) { ps->arr[i] = i; } //增容 struct s3* ptr = realloc(ps, sizeof(struct s3) + 80); if (ptr != NULL) { ps = ptr; } for (i = 10; i < 20; i++) { ps->arr[i] = i; } for (i = 0; i < 20; i++) { printf("%d ", ps->arr[i]); } //释放 free(ps); ps = NULL; //置空 return 0; }

另一种类似柔性数组的写法
struct s3//sizeof计算为8 { int num; int *arr; }; int main() { struct s3* ps = (struct s3*)malloc(sizeof(struct s3)); ps->arr = (int*)malloc(sizeof(int) * 5); int i = 0; //使用 for (i = 0; i < 5; i++) { ps->arr[i] = i; } //增容 int * ptr = realloc(ps->arr, 10*sizeof(int)); if (ptr != NULL) { ps->arr = ptr; } for (i = 5; i < 10; i++) { ps->arr[i] = i; } for (i = 0; i < 10; i++) { printf("%d ", ps->arr[i]); } //释放 free(ps->arr); free(ps); ps = NULL; //置空 return 0;

这两者的区别是
1.柔性数组所在的结构体大小为4,而下面这个结构体大小为8
2.柔性数组只存在于结构体中,而下面这个方法是通用的(动态开辟内存空间)

3.3柔性数组的优点
1.方便内存释放如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。2.有利于访问速度 .连续的内存有益于提高访问速度,也有益于减少内存碎片
由于多次使用malloc开辟的空间不一定是连续的,中间会存在一些空隙,我们把这些空隙称为内存碎片
笔记|动态内存管理(续)+柔性数组
文章图片

博主能力有限,如有误区,欢迎各位铁汁批评斧正
【笔记|动态内存管理(续)+柔性数组】今天就到这里吧,感谢观看哈

    推荐阅读