动态内存
我们已经懂得了开辟内存的方法:
int a = 10;
char b[10] = {0};
创建一个整型变量a,占用4个字节,一个有10个元素的char类型的数组b,占用连续的10个字节,但是以上开辟都是静态的,是固定死的,但有些时候我们只有再运行时才能知道需要多大的空间,就比如我们写一个通讯录,如果静态的开辟空间的话,假设我们开辟了一块可以存储100个联系人信息的空间,但是我们只有5个人的信息需要存储,这时就浪费了95个空间,而如果我们有120个人的信息需要存储,这时空间就会不足,所以这时候就会不灵活,到时空间的利用效率不高,这时候只能尝试动态开辟了。
动态内存函数
下面给大家介绍几个常用的动态内存函数:
malloc
开辟一块由你指定大小的空间,单位是字节,并返回一个void*的指针,需要注意的是malloc开辟空间可能存在失败,开辟空间失败会返回NULL。
库中的声明:
void *malloc( size_t size );
- size:表示要开辟的空间的大小,单位是字节
头文件:
#include <stdlib.h>
可以看到malloc返回的指针类型是一个void* 的指针,使用时应把malloc返回的指针强制转换为我们所需要的类型的指针,就好比如:
int main()
{
//开辟一块占用40个字节的空间,返回的指针强制转换为int*由ret接收
int* ret = (int*)malloc(40);
return 0;
}
//也可以这样写
int main()
{
//开辟一块占用40个字节的空间,返回的指针强制转换为int*由ret接收
int* ret = (int*)malloc(10 * sizeof(int));
return 0;
}
前面我们也提到了,malloc开辟空间可能会失败,而失败会返回NULL,所以我们在使用malloc开辟空间时,最好先判断一下返回的是不是NULL,如果开辟空间失败而不加以判断就使用的话,那么对NULL的使用和访问就都是非法的,所以应该这样加以判断:
int main()
{
int* a = NULL;
int* ret = (int*)malloc(10 * sizeof(int));
if(ret == NULL)
{
perror("malloc()");//头文件:<stdio.h> or <stdlib.h>
}
else
{
a = ret;
}
return 0;
}
在malloc开辟空间后,我们先把它的返回值存到ret里,然后判断ret是否为NULL,如果为NULL的话,就用perror这个函数输出错误信息,如果不为NULL的话,就把其赋值给a,a也就指向了这块动态开辟出来的空间。
下面是开辟空间失败的情况:
int main()
{
int* ret = (int*)malloc(INT_MAX);//INT_MAX头文件:#include<limits.h>
int* a = NULL;
if (ret == NULL)
{
perror("malloc()");
}
else
{
a = ret;
}
return 0;
}
错误信息:
可以看到,在我们要开辟INT_MAX那么大一块空间的时候,开辟失败了,而从错误信息中也可以清楚的了解到,没有足够的空间可以开辟,所以开辟失败,返回了NULL。
calloc
calloc实现的功能和malloc99%是一致的,只不过calloc会将开辟的空间全部初始化为0,而malloc则不会初始化。
库中的声明:
void *calloc( size_t num, size_t size );
- num:表示元素的个数
- size:表示每个元素的大小,单位是字节
头文件:
#include <stdlib.h>
calloc的使用方法和malloc是一致的,开辟失败返回NULL也是一致的,所以在使用时最好也能判断一下calloc返回的是否是NULL,唯一不同的就是calloc会把每个字节都初始化为0。
如下所示:
calloc:
malloc:
realloc
reallo函数使得动态内存的管理更加灵活,realloc的作用是扩大或者缩小动态开辟出来的空间,对空间的大小做出合适的调整。
库中的声明:
void *realloc( void *memblock, size_t size );
- memblock:指向动态开辟的内存块的指针
- size:调整后的大小,单位是字节
头文件:
#include <stdlib.h>
realloc在调整内存空间时会存在两种情况:
- memblock后面还有足够大的空间:
如果memblock后面还有足够的大小,足以放得下realloc调整后的空间的话,那么直接在原来的所占空间基础上接上要增加的空间即可。
- memblock后面没有足够大的空间:
假设memblock后面没有足够的空间,那么realloc就会另行开辟一块足够的空间,然后把你原来空间的数据都拷贝下来,在成功开辟的情况下返回一个地址,这样看起来就是既调整了空间,数据又没有发生变化。
free
free是对动态开辟的空间的释放,如果动态开辟的空间你已经不使用了,那么就要使用free来进行回收,如果只是一味的动态申请空间而不去释放归还的话,就可能会导致内存泄漏,导致不可预估的结果。
库中的声明:
void free( void *memblock );
- memblock:动态开辟空间的首地址
头文件:
#include <stdlib.h>
free使用注意事项:
- 如果不是动态开辟出来的空间,不能使用free来进行释放,因为没必要,释放不是动态开辟出来的空间这种写法是错误的!
- 如果memblock是NULL指针,那么free什么都不会做!
- 释放指针所指向的动态开辟的空间之后,一定要记得把它的指向置为NULL,如果不置为NULL,虽然空间释放了,但它还是保存了这个空间的地址,这样不安全。
举例:
int main()
{
//释放非动态开辟空间——error
char* str = "Hello World";
free(str);
//释放的指针所指向为NULL——什么事都不会做
int* arr = NULL;
free(arr);
//动态开辟出来的空间,一定要记得释放!!!
int* ary = (int*)malloc(66);
free(ary);
ary = NULL;
return 0;
}
结语
谢谢阅读,如果有哪里说的不对的地方,欢迎指出!!!