C语言——动态内存管理(2)经典笔试题+柔性数组

前言

(一)C/C++程序的内存开辟

(二)柔性数组

(三)动态内存管理——经典笔试题

1.C/C++程序的内存开辟
C语言——动态内存管理(2)经典笔试题+柔性数组_第1张图片

 (一)C/C++程序内存分配的几个区域:

1. 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结
束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是
分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返
回地址等。
2. 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分
配方式类似于链表。
3. 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
4. 代码段:存放函数体(类成员函数和全局函数)的二进制代码。

有了这幅图,我们就可以更好的理解在《C语言初识》中讲的static关键字修饰局部变量的例子了。

实际上普通的局部变量是在栈区分配空间的,栈区的特点是在上面创建的变量出了作用域就销毁。
但是被static修饰的变量存放在数据段(静态区),数据段的特点是在上面创建的变量,直到程序
结束才销毁
所以生命周期变长。

补充一点上一个博客里动态内存管理realloc的用法

realloc是调整申请的堆区内存的大小的,其实也可以像malloc一样申请开辟空间。

我们把第一个指针给为空指针。

C语言——动态内存管理(2)经典笔试题+柔性数组_第2张图片 

 

(二)柔性数组

也许你从来没有听说过柔性数组(flexible array)这个概念,但是它确实是存在的。
C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。

例如:

C语言——动态内存管理(2)经典笔试题+柔性数组_第3张图片

或者

C语言——动态内存管理(2)经典笔试题+柔性数组_第4张图片 

 在前面我们学过结构体的大小是内存对齐,联合的大小是共用一块空间,先求出各自的内存对齐大小,再减去联合体最大成员的数据类型即可,那么我们看看柔性数组的大小。

C语言——动态内存管理(2)经典笔试题+柔性数组_第5张图片

C语言——动态内存管理(2)经典笔试题+柔性数组_第6张图片 

 结果是8,是因为sizeof返回的这种结构大小不包括柔性数组的内存。

柔性数组的特点:

结构中的柔性数组成员前面必须至少一个其他成员。
sizeof 返回的这种结构大小不包括柔性数组的内存。
包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大
小,以适应柔性数组的预期大小。

那么柔性数组怎么使用呢?

C语言——动态内存管理(2)经典笔试题+柔性数组_第7张图片

C语言——动态内存管理(2)经典笔试题+柔性数组_第8张图片 

相当于sizeof(struct S)是给int n和char f申请堆区中内存的空间, 而10*sizeof(int)是给int arr[0]申请了40个字节的空间,相当于进化成了arr[10];

 C语言——动态内存管理(2)经典笔试题+柔性数组_第9张图片

 C语言——动态内存管理(2)经典笔试题+柔性数组_第10张图片

 

 C语言——动态内存管理(2)经典笔试题+柔性数组_第11张图片

 

我们也可以用realloc来重新调整柔性数组成员的大小

C语言——动态内存管理(2)经典笔试题+柔性数组_第12张图片

C语言——动态内存管理(2)经典笔试题+柔性数组_第13张图片 

C语言——动态内存管理(2)经典笔试题+柔性数组_第14张图片 

 我们再写另一种柔性数组的写法

这次用指针来表示柔性数组成员;

C语言——动态内存管理(2)经典笔试题+柔性数组_第15张图片

 C语言——动态内存管理(2)经典笔试题+柔性数组_第16张图片

C语言——动态内存管理(2)经典笔试题+柔性数组_第17张图片 

 C语言——动态内存管理(2)经典笔试题+柔性数组_第18张图片

 C语言——动态内存管理(2)经典笔试题+柔性数组_第19张图片

 C语言——动态内存管理(2)经典笔试题+柔性数组_第20张图片

C语言——动态内存管理(2)经典笔试题+柔性数组_第21张图片 

C语言——动态内存管理(2)经典笔试题+柔性数组_第22张图片 C语言——动态内存管理(2)经典笔试题+柔性数组_第23张图片

 因为两次malloc在堆区申请的空间不一定是连续的,中间可能会别的数据内存占据,内存碎片化就会增多。

C语言——动态内存管理(2)经典笔试题+柔性数组_第24张图片

第一个写法的好处是:方便内存释放
如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给
用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你
不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好
了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。

第二个好处是:这样有利于访问速度.
连续的内存有益于提高访问速度,也有益于减少内存碎片。(其实,我个人觉得也没多高了,反正
你跑不了要用做偏移量的加法来寻址。

(三)动态内存管理——经典笔试题

题目1

C语言——动态内存管理(2)经典笔试题+柔性数组_第25张图片

 C语言——动态内存管理(2)经典笔试题+柔性数组_第26张图片

C语言——动态内存管理(2)经典笔试题+柔性数组_第27张图片

 C语言——动态内存管理(2)经典笔试题+柔性数组_第28张图片

怎么修改才正确呢?

C语言——动态内存管理(2)经典笔试题+柔性数组_第29张图片 

C语言——动态内存管理(2)经典笔试题+柔性数组_第30张图片 

C语言——动态内存管理(2)经典笔试题+柔性数组_第31张图片 

 C语言——动态内存管理(2)经典笔试题+柔性数组_第32张图片

 题目2

C语言——动态内存管理(2)经典笔试题+柔性数组_第33张图片

 

 C语言——动态内存管理(2)经典笔试题+柔性数组_第34张图片

 

C语言——动态内存管理(2)经典笔试题+柔性数组_第35张图片

这是一个经典返回栈空间地址的问题

C语言——动态内存管理(2)经典笔试题+柔性数组_第36张图片 

 什么意思?我们写一段代码试一试

C语言——动态内存管理(2)经典笔试题+柔性数组_第37张图片

 C语言——动态内存管理(2)经典笔试题+柔性数组_第38张图片

 为什么会这样呢?因为栈帧空间被覆盖了。

C语言——动态内存管理(2)经典笔试题+柔性数组_第39张图片

 

 题目3:

C语言——动态内存管理(2)经典笔试题+柔性数组_第40张图片

这次的题目问题不大,只是没有free释放空间,造成内存泄漏。加个free(str),str=NULL;即可。

题目4:

C语言——动态内存管理(2)经典笔试题+柔性数组_第41张图片 

 没有把str置为空指针,下面的strcpy里面的str相当于非法访问=野指针。

你可能感兴趣的:(柔性数组,c语言,开发语言)