目录
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越多,内存碎片会增多,内存的使用率较低。
其实这里的内存节约也没多少,主要是理解其中特点。