c/c++程序的内存开辟
1.栈区:在执行函数时,函数的内部的储存单元都可以在栈上创建,结束时自动被释放。栈区的分配预案算内置预处理器模块,效率很高,但是分配的内存容量有限。存放不下就会产生栈溢出的现象。
栈区主要存放运行函数时被分配的局部变量,函数参数,返回数据,返回地址等
2.堆区:一般由程序员分配释放,若若程序员不释放,结束时可能被OS回收,分配方式类似链表。
3.数据段:也是静态区,存放全局变量,静态数据。程序结束时有系统释放。
4.代码段:存放函数体(类成员函数和全局函数)的二进制代码。
realloc函数补充
realloc也可以像malloc一样申请空间
若第一个参数给的不是所扩容的指针,而是空指针,如realloc(NULL,20),那就是如malloc一样申请20个字节的空间。
柔性数组
在 c99中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员。
typedef struct st_type { int i; int a[0];//柔性数组成员 };
柔性数组特点1:
.结构体中柔性数组成员前面必须至少有一个其他成员
两种写法
typedef struct st_type { int i; int a[0];//柔性数组成员 }; //或者这样写 struct S { int n; char c; int arr[];//大小未知 };
柔性数组特点2:
.sizof返回的这种结构大小不包过柔性数组的内存
struct S { int n; char c; int arr[];//未知,不知道它该占多大空间 }; int main() { printf("%d", sizeof(struct S));//结果为8 }
这里的空间大小不会包括柔性数组成员的大小,大小计算参考之前结构体内容。
柔性数组特点3:
.包含柔性数组成员的结构用malloc函数惊醒内存分配,并且分配的内存应该大于结构体的大小,以适应柔性数组的大小。
在创建结构体变量时,这里创建结构体的方式发生了改变,用动态内存开辟它的空间。
struct S { int n; char c; int arr[]; }; int main() { //假设柔性数组里我们想放10个整型数据 struct S* ptr=(struct S*)malloc(sizeof(struct S)+10*sizeof(int)); if (ptr== NULL) { printf("%s\n", strerror(errno)); return 1; } //使用 ptr->n = 100; ptr->c = "w"; for (int i = 0; i < 10; i++) { ptr->arr[i] = i; printf("%d", ptr->arr[i]); } //调整数组大小 大小调整为20ge 整形 struct S* tmp = (struct S*)realloc(ptr, sizeof(struct S) + sizeof(int) * 20); if (tmp == NULL) { printf("%s\n", strerror(errno)); return 1; } //使用 ptr->n = 100; ptr->c = "w"; for (int i = 0; i < 20; i++) { ptr->arr[i] = i; printf("%d", ptr->arr[i]); } //释放 free(ptr); ptr - NULL; }
利用malloc函数开辟结构体空间大小。
这里的柔性数组成员类似 int arr[10]存放10个整形数据,但是因为该数组的空间是由malloc开辟的,因此我们可是使用realloc函数来对空间进行调整根据我们的需求
通过调整结构体大小动态调整数组大小,柔性可变,故为柔性数组。
通过指针实现柔性数组的动态特点。
这里开辟空间时,只能先开辟结构体的空间,再开辟结构体里指针的空间。
这里的两个例子作用都是存放一到十的10个整形数据,扩容后存放一到二十的20个整型数组。
struct S { int n; char c; int* arr; }; int main() { struct S* ptr = (struct S*)malloc(sizeof(struct S)); if (ptr == NULL) { printf("%s\n", strerror(errno)); return 1; } int* tmp = (int*)malloc(sizeof(int) * 10); if (ptr == NULL) { printf("%s\n", strerror(errno)); return 1; } else { ptr->arr = tmp;//把开辟出来的空间给结构体里的指针 } //使用 ptr->n = 100; ptr->c = "w"; for (int i = 0; i < 10; i++) { ptr->arr[i] = i; printf("%d", ptr->arr[i]); } //调整 int *pc=realloc(ptr->arr, sizeof(int) * 20); if (pc == NULL) { return 1; } else { ptr->arr = pc; } //在使用 ptr->n = 100; ptr->c = "w"; for (int i = 0; i < 20; i++) { ptr->arr[i] = i; printf("%d", ptr->arr[i]); } //释放 free(ptr->arr); ptr->arr = NULL; free(ptr); ptr = NULL; return 0; }
注意:这里再释放时,我们刚开始下开辟的是结构体的空间,后开辟的结构体中指针的空间(扩容也是对结构体里的指针),故释放先释放结构体中指针的空间,在释放结构体的空间。
两者的区别
方案一(柔性数组)
malloc一次,free一次
容易维护空间,不易出错,且malloc次数少,内存碎片少,空间利用率相对较高。
方案二(指针表示)
malloc两次,free两次,维护难度加大,容易出错
malooc越多,内存碎片会增多,内存的使用率较低。
其实这里的内存节约也没多少,主要是理解其中特点。