十、动态内存分配
动态内存是在堆区开辟空间
10.1 malloc函数
格式:void* malloc(size_t size)
size是开辟空间的字节数,malloc的返回值是一个空指针,是开辟空间的首字节地址
这里开辟了一个10个int大小的空间,并把首字节地址赋给p
void main()
{
int* p = (int*)malloc(10 * sizeof(int));
if (p==NULL)
{
printf("%s", strerror(errno));
}
else
{
for (int i = 0; i < 10; i++)
{
*(p+i) = i + 1;
}
for (int i = 0; i < 10; i++)
{
printf("%d\n", *(p+i));
}
}
}
打印结果:
1
2
3
4
5
6
7
8
9
10
10.2 free函数
free函数释放和回收动态内存,一般malloc和free函数要搭配使用
格式:void free(void* ptr)
注意:使用free()后只是释放了参数指针ptr指向的动态内存空间,但ptr仍然指向那片内存的首地址,仍然有通过ptr调用空间的可能。所以再free函数之后,还要将ptr变成空指针
free(p); //p是指向先前开辟的内存空间首地址
p=NULL;
10.3 calloc
calloc函数同样用于开辟动态内存空间,且会将开辟的空间自动初始化为0
格式:void* calloc (size_t num, size_t size);
num是要开辟的元素的个数,size是一个元素占的字节,返回开辟空间的首字节地址
void main()
{
int* p = calloc(10, sizeof(int));
for (int i = 0; i < 10; i++)
{
*(p + i) = i;
}
for (int i = 0; i < 10; i++)
{
printf("%d\n", *(p + i));
}
free(p);
p = NULL;
}
10.4 relalloc
relalloc用于扩大先前用malloc、calloc函数开辟好的动态内存
格式:void* realloc (void* ptr, size_t size);
ptr是先前已有的用malloc或者calloc函数开辟的空间的指针,size是重新定义空间的大小,返回值是重新开辟的空间的指针
使用realloc函数需要注意,realloc在追加空间时有三种情况:
1.先前开辟的动态内存空间后面还有足够的空间进行追加,或者说所需追加的空间小于先前开辟的动态内存空间后方闲置空间,那么此时relalloc函数将直接在后方追加开辟的空间,返回的地址就是先前开辟的空间的地址,即返回的地址=参数指针ptr
2.先前开辟的动态内存空间后方闲置的空间<追加的空间,此时realloc函数会重新找一片足够大的内存空间,并把原有的内容拷贝过去,此时返回的地址则不再是之前动态内存空间的地址,即返回指针 !=参数指针ptr。所以用realloc函数时最好将返回指针重新赋给ptr或者新的指针
p = realloc(p, 15*sizeof(int));
3.当参数size太大,realloc找不到开辟空间时会返回NULL,此时产生一个问题,如果像上面一行代码p = realloc(p, 40000*sizeof(int))将返回地址赋给原来的指针,那么执行完这行代码后p=NULL,就导致原来开辟的那块内存空间丢失了,再也无法通过p找到。所以用realloc函数时最好用下面这种代码
int* ptr = NULL;
ptr = realloc(p, 15*sizeof(int));
if (ptr != NULL)
{
p = ptr;
}
先用一个新的指针接收返回的地址,如果返回的不是空指针再赋给p
补充;可用realloc实现malloc的功能
int *p=realloc(NULL,40);//等价malloc(40)
10.5动态内存常见错误
10.5.1 对NULL指针解引用
10.5.2 动态内粗越界访问
10.5.3用free函数对非动态内存释放
10.5.4free函数释放部分动态内存
10.5.5free函数多次释放同一块动态内存
free(p);
p=NULL
10.5.6未释放动态开辟空间(内存泄漏)
10.6 关于动态内存的面试题
非法访问内存