免费门户网站,网站管理助手 1004,seo服务外包公司,wordpress删除评论别人前言#xff1a; 本文是对于动态内存管理知识后续的补充#xff0c;以及加深对其的理解。对于动态内存管理涉及的大部分知识在这篇文章中 ---- 【C进阶】 动态内存管理_Dream_Chaser#xff5e;的博客-CSDN博客 本文涉及的知识内容主要在两方面#xff1a; 简单解析C/C程序…前言 本文是对于动态内存管理知识后续的补充以及加深对其的理解。对于动态内存管理涉及的大部分知识在这篇文章中 ---- 【C进阶】 动态内存管理_Dream_Chaser的博客-CSDN博客 本文涉及的知识内容主要在两方面 简单解析C/C程序的内存开辟分析柔性数组的知识点 目录
前言
C/C程序的内存开辟区域
1.栈区stack
2. 堆区heap
3. 数据段静态区static
4. 代码段
柔性数组
柔性数组的特点
柔性数组的使用
柔性数组的优势 C/C程序的内存开辟区域
1.栈区stack
在执行函数时函数内局部变量的存储单元都可以在栈上创建函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中效率很高但是分配的内存容量有限。栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。 2. 堆区heap
一般由程序员分配释放 若程序员不释放程序结束时可能由OS回收 。分 配方式类似于链表。 3. 数据段静态区static
存放全局变量、静态数据。程序结束后由系统释放。 4. 代码段
存放函数体类成员函数和全局函数的二进制代码。 内存区域划分图: 有了这幅图我们就可以更好的理解在C语言初识中讲的 static 关键字修饰局部变量的例子了。 实际上普通的局部变量是在栈区分配空间的栈区的特点是在上面创建的变量出了作用域就销毁。 但是被static修饰的变量存放在数据段静态区数据段的特点是在上面创建的变量直到程序结束才销毁所以生命周期变长。 柔性数组 柔性数组Flexible Array是一种在编程语言中用于表示可变长度的数组的数据结构。它允许在声明数组时不指定数组的长度而是在运行时根据需要动态分配内存空间。 柔性数组最常见的应用是在C语言中。在C语言中柔性数组是一种特殊的结构体成员其长度可以在结构体实例化之前或之后进行动态调整。 C99 中结构中的最后一个元素允许是未知大小的数组这就叫做『柔性数组』成员。 啥意思呢用代码说话 在vs编译器环境下以下两种写法均支持 第一种写法使用空方括号[ ]是更常见和更符合标准的写法可以在大多数编译器环境下使用。 struct S
{int n;char c;int arr[];//柔性数组成员
}; 第二种写法指定大小为0在某些特定的编译器(vs)扩展中可能有效但不具有通用性和可移植性。 struct S
{int n;char c;int arr[0];//柔性数组成员(指定大小)
}; 柔性数组的特点 1️⃣结构中的柔性数组成员前面必须至少一个其他成员。 typedef struct st_type
{int i;//必须至少一个其他成员int a[0];//柔性数组成员
}type_a; 错误写法: struct SA
{int arr[];//柔性数组成员
}; 2️⃣sizeof 返回的这种结构大小不包括柔性数组的内存 struct S
{int n;char c;int arr[];//柔性数组成员
};
int main()
{printf(%d, sizeof(struct S));
}8 3️⃣包含柔性数组成员的结构用malloc ()函数进行内存的动态分配并且分配的内存应该大于结构的大小以适应柔性数组的预期大小。 #includestdio.h
#includestring.h
#includeerrno.h
#includestdlib.h
int main()
{//arr需要开辟的空间是10个int// n与c需要开辟的内存 arr数组需要开辟的内存空间// 8 40struct S* ps (struct S*)malloc(sizeof(struct S) 10 * sizeof(int));return 0;
} 图解: 柔性数组的使用 代码实现 #includestdio.h
#includestring.h
#includeerrno.h
#includestdlib.h//柔性数组
struct S
{int n;char c;int arr[];//柔性数组成员
};int main()
{struct S* ps (struct S*)malloc(sizeof(struct S) 10 * sizeof(int));if (ps NULL){printf(%s\n,strerror(errno));return 1;}//使用ps-n 100;ps-c w;int i 0;for ( i 0; i 10; i){ps-arr[i] i;}for (i 0; i 10; i){printf(%d\n, ps-arr[i]);}//调整arr数组的大小(注意这是重新改变大小不是说在原来空间后面增加比如说原来是48那么现在就是88)struct S* ptr (struct S*)realloc(ps, sizeof(struct S) 20 * sizeof(int));if (ptr NULL){printf(%s\n,sterror(error));return 1;}else{ps ptr;}//再次使用//....//释放free(ps);ps NULL;printf(%d\n, sizeof(struct S));return 0;
}调试一下看看空间大小如何 malloc的空间,58-3028(16进制)换成十进制刚好为40刚好是10int的字节大小 柔性数组的优势
方案一:柔性数组的方案
#includestdio.h
#includestring.h
#includeerrno.h
#includestdlib.h//柔性数组
struct S
{int n;char c;int arr[];//柔性数组成员
};int main()
{struct S* ps (struct S*)malloc(sizeof(struct S) 10 * sizeof(int));if (ps NULL){printf(%s\n,strerror(errno));return 1;}//使用ps-n 100;ps-c w;int i 0;for ( i 0; i 10; i){ps-arr[i] i;}for (i 0; i 10; i){printf(%d\n, ps-arr[i]);}//调整arr数组的大小(注意这是重新改变大小不是说在原来空间后面增加比如说原来是48那么现在就是88)struct S* ptr (struct S*)realloc(ps, sizeof(struct S) 20 * sizeof(int));if (ptr NULL){printf(%s\n,sterror(error));return 1;}else{ps ptr;}//再次使用//....//释放free(ps);ps NULL;printf(%d\n, sizeof(struct S));return 0;
}描述: malloc 1次 free 1次 方案二:结构中指针方案 定义一个指针变量指向一块新的区域,像下面这样 图解: 代码实现✨
struct S
{int n;char c;int* arr;
};int main()
{struct S* ps (struct S*)malloc(sizeof(struct S));if (ps NULL){perror(malloc);return 1;}int* ptr (int*)malloc(10 * sizeof(int));if (ptr NULL){perror(malloc2);return 1;}else{ps-arr ptr;}//使用ps-n 100;ps-c w;int i 0;for (i 0; i 10; i){ps-arr[i] i;}//打印for (i 0; i 10; i){printf(%d ,ps-arr[i]);}//扩容 - 调整arr的大小ptr realloc(ps-arr,20*sizeof(int));if (ptr NULL){perror(realloc);return 1;}else{ps-arr ptr;}//使用//释放free(ps-arr);ps-arr NULL;free(ps);ps NULL;return 0;
}描述: malloc 2次free 2次 上面的方案一和方案二谁的优势更优呢,显然是方案一。
个人的理解: 从写代码的方面来说malloc越多free的越多空间的维护难度就更高所以 方案一实现起来更加简单空间维护更加简单容易维护空间不易出错 方案二来说,一旦忘记free一次的话,可能会导致内存泄漏等问题所以维护难度加大容易出错 还有区别就是: 在堆区上申请内存的话每一次malloc申请的空间第二次malloc申请的空间跟第一次申请的空间在地址上不一定是连续的,随机性很高随着malloc申请的数量越多那么在内存和内存之间留下的空隙就会越多这种空隙我们叫做为内存碎片 因为这种内存碎片空间大小比较小一些那么未来可能被利用到的概率就会比较低一些所以说内存碎片越多那么内存利用率就会越低 总结 ①方案一:malloc次数少内存碎片就会较少内存的使用率就较高一些 ②方案二:malloc次数多内存碎片就会增多内存的使用率就下降了 上述 方案 1 和 方案 2 可以完成同样的功能但是 方法 1 的实现有两个好处 ⛳第一个好处是 方便内存释放 如果我们的代码是在一个给别人用的函数中你在里面做了二次内存分配并把整个结构体返回给用户。用户调用free可以释放结构体但是用户并不知道这个结构体内的成员也需要free所以你不能指望用户来发现这个事。所以 如果我们把结构体的内存以及其成员要的内存一次性分配好了并返回给用户一个结构体指针用户做一次free就可以把所有的内存也给释放掉。 ⛳第二个好处是 这样有利于访问速度 . 连续的内存有益于提高访问速度也有益于减少内存碎片。其实我个人觉得也没多高了反正你跑不了要用做偏移量的加法来寻址) 本文结束如有错误欢迎指正感谢支持