💐2.C语言动态内存管理库函数应用
🌿🌿2.1常见相关笔试题
💐题目一:请问运行Test 函数会有什么样的结果?
char *GetMemory(void) { char p[] = "hello world"; return p; } void Test(void) { char *str = NULL; str = GetMemory(); printf(str); }
💐分析:程序运行极大可能打印随机值
由于p是一个局部变量,因此当其出了函数GetMemory之后就会销毁,虽然在销毁之前将地址返回给str,但str维护的是一块野指针,因此str就会非法访问内存.
这类问题属于返回栈空间地址的问题。栈空间的地址不能轻易返回,因为一旦出了作用域之后就被销毁了。
💐题目二:请问运行Test 函数会有什么样的结果?
void GetMemory(char *p) { p = (char *)malloc(100); } void Test(void) { char *str = NULL; GetMemory(str); strcpy(str, "hello world"); printf(str); }
💐分析:程序运行打印随机值
函数GetMemory的形参为char* p,p为该函数的局部变量,作用域在函数内部,出了函数该变量就被销毁了,并且没有对申请好的内存进行释放。所以参数str传入函数GetMemory后,其值不会改变,仍为NULL,空地址是不能被用户访问修改的,因此程序崩溃。
💐题目三:请问运行Test 函数会有什么样的结果?
void GetMemory(char **p, int num) { *p = (char *)malloc(num); } void Test(void) { char *str = NULL; GetMemory(&str, 100); strcpy(str, "hello"); printf(str); }
💐分析:该程序虽然会输出hello
,但是是存在内存泄漏的,因为最后并没有释放申请的内存。
正确写法应该是:
void GetMemory(char **p, int num) { *p = (char *)malloc(num); } void Test(void) { char *str = NULL; GetMemory(&str, 100); strcpy(str, "hello"); printf(str); free(str); str=NULL; }
💐题目四:请问运行Test 函数会有什么样的结果?
void Test(void) { char *str = (char *) malloc(100); strcpy(str, "hello"); free(str); if(str != NULL) { strcpy(str, "world"); printf(str); } }
💐分析:由于free完没有置为NULL空指针,因此错误。
正确写法:
void Test(void) { char *str = (char *) malloc(100); strcpy(str, "hello"); free(str); str=NULL; }
🌿🌿2.2C/C++语言中的内存开辟
栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行 结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但 是分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、 返回地址等。
堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分
配方式类似于链表。
数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
代码段:存放函数体(类成员函数和全局函数)的二进制代码。
🌿🌿2.3柔性数组
也许你从来没有听说过柔性数组(flexible array)这个概念,但是它确实是存在的。
在C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。
🌺🌺🌺2.3.1柔性数组特点与使用
typedef struct st_type { int i; int a[]; //柔性数组成员 }type_a;
💐注意事项:
- 结构中的柔性数组成员前面必须至少一个其他成员。
sizeof
返回的这种结构大小不包括柔性数组的内存。- 包含柔性数组成员的结构用
malloc ()
函数进行内存的动态分配,并且分配的内存应该大于结构的大
小,以适应柔性数组的预期大小。
💐举个栗子:
typedef struct st_type { int i; int a[0];//柔性数组成员 }type_a; printf("%d\n", sizeof(type_a));//输出的是4
这里输出的是4,不包括柔性数组的大小。
💐为柔性数组开辟空间
int i = 0; type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int)); //业务处理 p->i = 100; for(i=0; i<100; i++) { p->a[i] = i; } free(p);
这里使用malloc为柔性数组开辟空间,100*sizeof(int)就是开辟了柔性数组的空间。
这样柔性数组成员a,相当于获得了100个整型元素的连续空间。
🌺🌺🌺2.3.2柔性数组的优点
💐第一个好处是:方便内存释放
如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回 给用户。
用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这事。如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。
💐 第二个好处是:这样有利于访问速度.
连续的内存有益于提高访问速度,也有益于减少内存碎片。