改错误
//下面这个代码中sp指针指向的空间为只读空间
//不能对这个空间进行修改
char *sp ="yhping";
//错误 sp指向空间不能修改
strcpy(sp,"ya");
//这个可以修改
char stra[100];
//这段代码是正确的
strcpy(stra,"ya");
- 对动态开辟的空间进行释放之后,如果再次释放有可能会导致系统崩溃
- 动态开辟内存之后,需要对返回的首地址进行判空,在使用完成之后,要对其进行释放,并且对其首地址指向空,否则会出现严重后果
堆区和栈区的区别
- 管理方式:栈由函数自动管理,堆区由程序员自己控制
- 生长方式:栈区是由高地址向低地址进行扩展,向下生长;堆区是由低地址向高地址生长,向上生长;
- 空间大小:栈空间小,1M或者10M;堆区大小取决于系统有效的虚拟内存
- 存储内容:栈存储函数调用相关的数据,和保护现场相关的数据;堆所放数据没太大要求
- 分配方式:栈可以静态分配或者动态分配,比如定义的局部变量在函数调用就分配空间了,动态分配alloca函数分配,用完空间之后不需要调用free释放,自动释放;堆只能手动分配和释放
- 分配效率:栈分配效率比堆分配效率高
- 分配后系统响应:只要栈空间足够,系统就会为程序提供内存,否则就报栈溢出;堆:遍历该链表第一个满足所需空间的链表的头结点,将头结点从空闲链表中删除,然后返回这个节点,大多数系统会记录该内存空间的分配空间的大小,以便正确的释放本内存空间
- 碎片问题:栈不会产生碎片问题;而堆会产生内存碎片
由上面可以看出堆的效率和碎片方面都不如栈,所以栈的应用更广一点
动态内存管理与结构体
- 结构体变量和内置类型都有全局、局部、动态生存期概念
- 对于未初始化的结构体,会将其放在.data区域内部的.bss区域,这个区域专门存放未初始化的变量,将其里面每个字节都填充0值,那么这个结构体中所有的变量都被初始化为0值
- 结构体可以嵌套指向自身的的指针,如果不写成指针,那么会出现逐渐嵌套下去的效果
可以通过堆区的malloc将结构体连起来
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Student {
char str[20];
struct Student* next;
};
int main() {
struct Student* p = nullptr;
p = (struct Student*)malloc(sizeof(struct Student));
strcpy(p->str, "asd");
struct Student* s = nullptr;
s = (struct Student*)malloc(sizeof(struct Student));
strcpy(s->str, "ad");
s->next = p;
p = s;
return 0;
}
柔性数组
- c99中定义了新的设计方法,通过柔性数组来解决开辟数组空间远远大于实际需求导致空间浪费这一问题
struct sd_node {
int num;
int size;
char data[];
};
struct sd_node {
int num;
int size;
char data[0];
};
注意
:全局数组和局部数组不能这样定义
- 在结构体中可以采用结构体产生柔性数组,
结构体的最后一个元素可以是大小未知的数组
- 柔性数组不占用空间,在结构体中只是代表一个偏移量的概念
struct sd_node* sp = (struct sd_node*)malloc(sizeof(struct sd_node) + 100);
其分配的空间如下:
在结构体最后的空间偏移了100个空间,用作data数组的空间
- 柔性数组和指针相比在结构体中的好处在哪?
指针分配的是指针空间还需要指向某个区域的数据,需要调用两次malloc函数,第一次是给结构体malloc,第二次是给存放指针指向区域malloc;而柔型数组直接就一次性分配合适的空间,效率更高、更方便