4.经典笔试题
4.1 题目一
void Memory(char* ptr) { ptr = (char*)malloc(20); } void test() { char* p = NULL; Memory(p); strcpy(p, "crush"); printf(p); } int main() { test(); return 0; }
1.当程序开辟动态内存退出函数Memory时,临时变量ptr被销毁,开辟的动态内存没有被释放,再也找不到,由此造成内存泄漏。 2.p是空指针,strcpy执行时,会对p解引用然后会崩溃的
4.2 题目二
char* Memory() { char ch[] = "hello crush"; return ch; } void test() { char* p = NULL; p = Memory(); printf(p); } int main() { test(); return 0; }
当程序离开函数 Memory时,数组 char ch[]就会被销毁,所以指针 p接收到一块不明内容的地址,打印结果就是未知的,也就是野指针。
4.3 题目三
void Memory(char** ptr, int num) { *ptr = (char*)malloc(num); } void test() { char* p = NULL; Memory(&p, 20); strcpy(p, "crush"); printf(p); } int main() { test(); return 0; }
唯一的缺点就是没有对开辟的动态内存进行释放,和将指针置为空指针。
4.4 题目四
void test() { char* p = (char*)malloc(20); strcpy(p, "crush"); free(p); if (p != NULL) { strcpy(p, "crush"); printf(p); } } int main() { test(); return 0; }
典型野指针,动态开辟的内存被释放之后,指针 p只能记得地址,但不能继续使用,因此变成野指针。
5.柔性数组
C99标准中,结构体中最后一个元素允许是未知大小的数组,称作柔性数组
struct M { int i; int arr[];//柔性数组 };
5.1柔性数组的特点
1. 结构体中的柔性数组成员前面必须至少一个其他成员 2. sizeof返回结构体大小时,不包括柔性数组的内存 3. 包含柔性数组的结构体需要用malloc()函数进行内存的动态分配 并且分配的内存必须大于结构体的大小,以满足柔性数组对内存的需求
struct M { int i; int arr[];//柔性数组 }; int main() { printf("%d\n", sizeof(struct M)); return 0; }
5.2柔性数组的使用
#include<stdio.h> #include<string.h> #include<errno.h> struct M { int n; int arr[];//柔性数组 }; int main() { //柔性数组的使用 struct M* p = (struct M*)malloc(sizeof(struct M) + 20); if (p == NULL) { printf("%s\n", strerror(errno)); return; } p->n = 0; int i = 0; for (i = 0; i < 5; i++) { p->arr[i] = i; } for (i = 0; i < 5; i++) { printf("%d ", p->arr[i]); } printf("\n"); //扩容 struct M* ptr = (struct M*)realloc(p, 40); if (ptr != NULL) { p = ptr; } //释放内存 free(p); p = NULL; return 0; }
类似柔性数组的使用方法
#include<stdio.h> #include<string.h> #include<errno.h> struct M { int n; int* arr; }; int main() { //动态内存开辟 struct M* p = (struct M*)malloc(sizeof(struct M)); if (p == NULL) { printf("%s\n", strerror(errno)); return; } p->n = 0; p->arr = (int*)malloc(20); int i = 0; for (i = 0; i < 5; i++) { p->arr[i] = i; } for (i = 0; i < 5; i++) { printf("%d ", p->arr[i]); } //扩容 int* ptr = (int*)realloc(p->arr, 40); if (ptr != NULL) { p->arr = ptr; } //释放 free(p->arr); free(p); p = NULL; return 0; }
5.3柔性数组的优点
上面两种方法都可以实现相同的目的-柔性数组的使用
相比之下,还是第一种方法更好一些
优点1:方便内存释放
第一种方法只需要释放一次内存即可,而第二种方法需要释放两次
优点2:访问速度更快
连续的内存有利于提高访问速度,也有利于减少内存碎片