@TOC
序言
在C语言中,我们经常使用数组,但是当我们使用数组时,我们在内存中开辟的大小已经固定下来的,所以这就引出今天的内容 -- 动态内存开辟
动态内存
什么是动态内存开辟
说的简单点就是我们可以任意开辟我们的空间,即使后期我们发现内存不够用了也可以继续增加
动态内存的特点是什么
数组是在栈区上开辟空间,而动态内存是在堆区上开辟空间
如何进行动态内存开辟
在这里C语言提供了三个函数,这些函数都在标准库stdlib.h,他们分别有各自的作用,我这里先让大家认识一下,后面细说
- malloc 函数
- calloc 函数
- realloc 函数
malloc函数
malloc 所执行的内存分配基于字节数而不是类型,其返回类型为 void 指针(void *),表示该指针所指向区域的数据类型未知。C++ 由于其强类型系统,实际使用该指针时需要进行强制类型转换,而 C 语言中则不必进行。
例一
开辟一个40个字节的空间,将1-10放到空间中
int main()
{
int* p = (int*)malloc(40);
if (p != NULL)
{
for (int i = 0; i < 10; i++)
{
p[i] = i + 1;
}
for (int i = 0; i < 10; i++)
{
printf("%d ", p[i]);
}
}
free(p);
p = NULL;
return 0;
}
这里我们会发现一些和我们期望不太一样的东西,我们一点点说
判断开辟的空间是不是空指针
实际上如果我们开辟的空间太大,我们是开辟不出来的,而且编译器会给我们返回一个NULL
int main()
{
int* p = (int*)malloc(1000000000000000000);
if (p == NULL)
{
printf("开辟的空间太大,无法开辟\n");
}
return 0;
}
free
正所谓有借有还,内存也是如此,我们开辟的了空间后,要是不再使用了应该将他释放掉,要不然这块空间被占据着,无法被其他人使用
free的作用就是将它的空间释放掉
将释放的变量置为NULL
当我们free掉内存空间后,p仍旧指向这片空间,要是我们不小心再次使用,就会发生非法访问,就像你的前女/男友一样,你或许记者她/他的号码,要是你再骚扰她/他,这就很不地道
int main()
{
int* p = (int*)malloc(40);
printf("%p\n", p);
free(p);
printf("%p\n", p);
return 0;
}
calloc函数
calloc函数和malloc函数作用差不多,不过参数有些不同
参数不同
void *calloc( size_t num, size_t size );
- size_t num 表示要开辟的个数
- size_t size表示开辟一个占据的字节数
int p = (int)calloc(4,4)表示开辟四个,每个占据4个字节
作用有些差异
- malloc开辟的空间里面是随机值
- calloc开辟的空间并且初始化了,初始化为0
int main()
{
int* p = (int*)calloc(4,4);
if (p != NULL)
{
printf("%d %d %d %d\n", p[0], p[1], p[2], p[3]);
}
free(p);
p = NULL;
return 0;
}
realloc函数
要是前面两个函数是开辟,纳么realloc函数可以理解为追加,要是我们第一次开辟的空间太小,我们就可以使用realloc函数进行扩大
参数
void realloc( void memblock, size_t size );
- void *memblock 第一次开辟空间的地址,要是没有第一次开辟,可以写成NULL 相当于第一次开辟了
- size_t size 开辟空间的总大小 == 第一次的 + 追加的
首次开辟
int main()
{
int* p = (int*)realloc(NULL, 80);
free(p);
p = NULL;
return 0;
}
追加
int main()
{
int* p = (int*)malloc(40);
int* tmp = (int*)realloc(p, 80);
if (tmp != NULL)
{
p = tmp;
}
free(p);
p = NULL;
return 0;
}
realloc重新开辟
要是我们追加的空间太大,编译器会自动开辟一块新的内存,并且将第一次开辟的值赋到新空间中,要是够了,就在后面追加
int main()
{
int* p = (int*)malloc(40);
if (p == NULL)
{
return 0;
}
for (int i = 0; i < 10; i++)
{
p[i] = i + 1;
}
int* tmp = (int*)realloc(p, 8000);
if (tmp != NULL)
{
if (tmp == p)
{
printf("为重新开辟\n");
}
else
{
printf("重新开辟了了一块新内存\n");
for (int i = 0; i < 10; i++)
{
printf("%d ", tmp[i]);
}
}
p = tmp;
}
free(p);
p = NULL;
return 0;
}
总结
- 每次开辟后不用了一定要free掉
- 三个函数的返回值都是void* ,参数不同