1. 动态内存的重要性
有些时候,我们需要的空间大小只有在程序运行的时候才能知道,而普通的数组开辟的空间是指定长度的,固定不变的,这就带来了不便。
2.动态内存函数的
2.1 malloc
void* malloc(size_t size);
- malloc可以向内存申请一块连续的内存,并且返回指向这块空间的指针。
- 如果开辟空间失败,malloc会返回一个NULL指针,因此对于malloc的返回值一定要记得检查。
- 由于系统不知道使用者对于申请空间的用处,所以返回的是一个void*类型的指针,让使用者在使用时自己去强制转换
malloc的参数代表开辟多大的字节,如果为0,结果不定,取决于编译器
2.2 free
void* free(void* ptr);
- C语言中所有动态开辟的空间都需要释放和回收,而free函数就是专门做这个工作的。
- 如果free释放的空间不是动态开辟的,那么结果是未知的
- 如果参数ptr为NULL,那么free函数什么都不做
- 释放内存过后要将ptr=NULL;
2.3 calloc
void* calloc(size_t num,size_t size);
calloc函数和malloc的功能大同小异,都是开辟一块指定大小的内存空间,不同的是
- calloc开辟的空间会将每个字节都初始化为0
- calloc所需参数与malloc不同,calloc会开辟num个size大小的空间,也就是说,calloc开辟的空间大小是num*size
2.4 realloc
void* realloc(void* ptr,size_t size)
- realloc函数是让内存动起来的关键,使用它可以根据需要来动态地调整动态空间的大小。
- realloc会把ptr指向的空间大小修改为size大小,并返回指向更新后空间地址的指针
- realloc的使用会有两种情况:
- 原有空间的后面有足够大的空间,那么扩容时就单纯的追加空间即可
- 原有空间的后面没有足够大的空间,那么扩容时就要找到一块新的空间来开辟,将之前空间里的数据复制过来,这块新的空间直接就是size大小,因此realloc函数有时会返回一个新的地址
3. 动态内存使用时的一些典型错误
3.1 对NULL指针解引用
void test()
{
int* p=(int*)malloc(10);
*p=20;
free(p);
}
这个代码的问题在于,如果malloc开辟空间失败,那么*p=20就是对NULL指针解引用,是错误的
3.2 用free释放非动态空间
void test()
{
int a=10;
int* p=&a;
free(p);
}
3.3 用free释放动态空间的一部分
void test()
{
int* p=(int*)malloc(100);
p++;
free(p);
}
p已经不指向这块内存的起始位置,所以不能将p传给free来释放
3.4 用free多次释放动态空间
void test()
{
int* p=(int*)malloc(100);
free(p);
free(p);
}
p第一次释放过后还没有置空,不能再释放第二次
3.5 未释放动态内存
void test()
{
int* p=(int*)malloc(100);
}
忘记释放的动态内存会造成内存泄漏
4.动态内存笔试题
4.1
void Getmemory(char* p)
{
p=(char*)malloc(100);
}
void test()
{
char* str=NULL;
GetMemory(str);
strcpy(str,"hello world");
printf(str);
}
这个程序会打印出hello world
吗?
是不行的
因为GetMemory(char* p)
是接收一个指针变量,并将一块空间的地址赋给这个指针,但是在函数中,这个指针p
只是str
这个实参的一个临时复制,它出了GetMemory
这个函数就会销毁,所以malloc开辟的这块空间就没有指针指向他了,str
还是一个NULL
指针
4.2 返回栈空间地址问题
void Getmemory(char* p)
{
char p[]="hello world";
return p;
}
void test()
{
char* str=NULL;
str=GetMemory();
printf(str);
}
这个程序会打印出hello world
吗?
同样是不行的
出了这个函数,p
指向的空间被系统收回,str称为野指针
5.柔性数组
5.1定义
C99中,结构体中最后一个元素允许是未知大小的数组,这就叫做柔性数组
struct s
{
int i;
int a[0];//这就是柔性数组成员
};
struct s
{
int i;
int a[];//这也是柔性数组成员
};
5.2 特点
- 柔性数组成员前必须有至少一个其他成员
sizeof
计算的结构体大小不包括柔性数组成员的内存大小- 含有柔性数组的结构体应用malloc()函数进行内存分配
typedef struct S
{
int i;
int a[];
}S;
S* p=malloc(sizeof(S)+10*sizeof(int));
p->i=100;
for(i=0;i<100;i++)
{
p->a[i]=i;
}
free(p);
相当于获得了100个整型元素的连续空间