三、经典例题分析
3.1题目1
void GetMemory(char* p) { p = (char*)malloc(100); } void Test(void) { char* str = NULL; GetMemory(str); strcpy(str, "hello world"); printf(str); } int main() { test(); return 0; }
运行程序时,会报出错误,这是什么原因呢。
1.对NULL指针进行解引用操作,程序会崩溃。
2.没有释放空间,存在内存泄漏问题。
3.2 题目2
char *GetMemory(void) { char p[] = "hello world"; return p; } void Test(void) { char *str = NULL; str = GetMemory(); printf(str); } int main() { Test(); return 0; }
可以用static修饰变量p,使p的声明周期变长。
3.3题目3:
void GetMemory(char **p, int num) { *p = (char *)malloc(num); } void Test(void) { char *str = NULL; GetMemory(&str, 100); strcpy(str, "hello"); printf(str); } int main() { Test(); return 0; }
四、C/C++程序的内存开辟
C/C++程序内存分配的几个区域:
1. 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结 束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是 分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
2. 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分配方式类似于链表。
3. 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
4. 代码段:存放函数体(类成员函数和全局函数)的二进制代码。
五、柔性数组
5.1什么是柔性数组
C99 中,结构体中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员。
例如:
typedef struct st_type { int i; int a[0];//柔性数组成员 }type_a;
注意:柔性数组这个结构中,柔性数组前至少有一个成员。
5.2柔性数组的特点
- 结构中的柔性数组成员前面必须至少一个其他成员。
- sizeof 返回的这种结构大小不包括柔性数组的内存。
- 包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
5.3柔性数组的使用
我们开辟好空间后,发现空间不够用,我们可以使用realloc增容。
struct S { int n; int arr[]; }; int main() { struct S* p = (struct S*)malloc(sizeof(struct S) + 40); if (p == NULL) { perror("malloc"); return 1; } p->n = 100; int i = 0; for (i = 0; i < 10; i++) { p->arr[i] = i + 1; } //释放 free(p); p = NULL; }
替代柔性数组:
struct S { int n; int* arr; }; int main() { struct S* p = (struct S*)malloc(sizeof(struct S)); if (p == NULL) { perror("malloc"); return 1; } p->n = 100; p->arr = (int*)malloc(40); if (p->arr == NULL) { perror("malloc"); return 1; } int i = 0; for (i = 0; i < 10; i++) { p->arr[i] = i + 1; } //增容 int* ptr = (int*)realloc(p->arr, + 60); if (ptr == NULL) { perror("realloc"); return 1; } p->arr = ptr; for (i = 0; i < 15; i++) { printf("%d ", p->arr[i]); } //释放 free(p->arr); p->arr = NULL; free(p); p = NULL; return 0; }
要先释放里面的,再释放外面的。如果先把p释放了,就找不到arr的地址了。
5.4柔性数组的优点
我们上面的代码二,可以完美的替代柔性数组的功能,却为什么还是创造除了柔性数组呢。在这就要说到柔性数组的优点:
1.内存方便释放
在柔性数组中,我们只使用了一次malloc,方法二中使用了两次malloc,容易造成忘记释放,没有都释放或释放顺序错误的问题。
2.访问速度快,节省空间
多次开辟空间,内存与内存之间的内存碎片会很多,不内存的利用率就会变低。同时,连续的内存有益于提高访问速度。
本次的内容到这里就结束啦。希望大家阅读完可以有所收获,同时也感谢各位读者的支持。文章有问题可以在评论区留言,博主一定认真认真修改,以后写出更好的文章。