在考研复习二轮的数据结构的时候,发现一个之前比较模糊的点,今天来补补课。
动态内存分配
不放过每一个值得关注的点
前言
我们创建一个一维的数组的时候,可以是静态分配的,也可以是动态分配的。
静态分配时,如果不能很好的把握数组的大小,有可能会出现数据量较小,浪费空间;
或者是空间较小,数据溢出导致程序崩溃的情况。
而动态分配时,存储数组的空间是在程序执行过程中通过动态存储分配语句分配的,
一旦数据空间占满,就开辟一块更大的存储空间,以替换原来的存储空间,从而达到扩充存储空间的目的;
一、malloc函数
malloc()函数会在堆内存中申请一整片连续的存储空间;
如果申请成功,返回一整片连续存储空间的起始地址,否则返回NULL;
堆在所有的线程,共享库,和动态加载的模块中被共享使用
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
int main() {
int *p = NULL;
printf("初始化指针%p\n",p);
p = (int *) malloc(sizeof(int)*10);
if(p != NULL)
printf("一整片存储空间的起始地址%p\n",p);
return 0;
}
运行结果:
这里注意一下,指针的初始化和判空操作;
这里内存空间的申请的过程是这样的:
操作系统有记录空闲内存地址的链表;
当程序发出“申请空间”的指令的时候,就会遍历链表,找到空间满足的结点;
把这个结点从链表中删除,这块空间我们就得到了。
二、free()函数
在栈中存储局部变量,函数调用完的时候系统就会自动释放内存;
但是在堆中申请内存空间,我们不手动释放,直到程序运行完的时候才会释放内存,这样可能会造成内存泄露(这片区域的数据的时效性已经过去了,但是还是占用空间),及时送神哈。
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
int main() {
struct student{
int number;
char *name;
char sex;
float score;
} *stu;
stu = (struct student*)malloc(sizeof(struct student));
printf("申请的空间的地址 %p\n",stu);
if(stu != NULL){
stu ->number = 24;
stu ->name = "**浩";
stu -> sex = 'm';
stu ->score =89.5;
printf("{number = %d name = %s sex=%c score = %f }\n",stu->number,stu->name,stu->sex,stu->score);
}
free(stu);
printf("释放后指向的空间地址 %p\n",stu);
stu = NULL;
printf("指向的空间的地址 %p\n",stu);
return 0;
}
运行结果:
- stu是空指针,函数不执行任何操作;
- 函数释放指针结束后,指针指向的地址没有改变(内存空间已经释放);
- 函数之后需要对指针置空(stu = NULL),如果不置空的话,stu会访问到已经释放的空间,会出现信息错误的情况。如下:
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
int main() {
struct student{
int number;
char *name;
char sex;
float score;
} *stu;
stu = (struct student*)malloc(sizeof(struct student));
if(stu != NULL){
stu ->number = 24;
stu ->name = "**浩";
stu -> sex = 'm';
stu ->score =89;
printf("{number = %d name = %s sex=%c score = %f }\n",stu->number,stu->name,stu->sex,stu->score);
}
free(stu);
printf("释放内存后访问{number = %d name = %s sex=%c score = %f }\n",stu->number,stu->name,stu->sex,stu->score);
return 0;
}
运行结果: