C语言|空间用多少我说了算! C语言动态内存!


空间大小我说了算--动态内存

  • 为什么存在内存分配
  • malloc 开辟空间 free 释放空间
    • malloc
    • free
  • calloc 开辟空间
  • realloc 管理内存
    • realloc 调整内存的两种情况
      • 情况1:原有空间之后有足够大的空间
      • 原有空间之后没有足够大的空间
    • realloc 使用代码示例

为什么存在内存分配 我们之前学的内存分配,都是直接开辟内存。但是这样有一个问题:我们开辟的内存是大了还是小了,会不会浪费,会不会不够用。有的程序只有在运行的时候才知道要用多少空间。所以为了解决这样的问题,我们就有了内存的动态开辟。
动态内存都是在堆区上面的,外面操作动态内存的,malloc free calloc realloc 也都是对堆区的内存进行操作。
malloc 开辟空间 free 释放空间 malloc malloc 是C语言提供的动态内存开辟函数。
viod* malloc(size_t size);

malloc 申请的是连续的空间。如果开辟成功,那么返回的就是开辟的内存的起始地址。如果开辟失败,就返回 NULL 。返回值的类型是 void* 因为 malloc 不知道开辟的内存是什么类型。所以我们使用的时候,可以强制类型转换一下。转换为我们要使用的类型。例如:我们开辟整型内存。
int* p = (int*)malloc(10*sizeof(int));

free free 就是对开辟的堆区空间进行释放。每次 free 释放内存之后,一定要把指针变量置为 NULL 防止出现野指针。用法如下:
int* p = (int*)malloc(10*sizeof(int)); free(p); p = NULL;

使用一个变量来开辟空间,这里使用一个变量 num 来开辟一段动态空间:
int main() { int num = 0; scanf("%d", &num); int* ptr = (int*)malloc(num * sizeof(int)); if (ptr != NULL) {int i = 0; for (i = 0; i < num; i++) {*(ptr + i) = i + 1; } for (i = 0; i < num; i++) {printf("%d ", *(ptr + i)); } } free(ptr); ptr = NULL; return 0; }

C语言|空间用多少我说了算! C语言动态内存!
文章图片

这里就是通过输入一个数 num 然后开辟相应的内存空间。并且赋值为 1 - 10 。
calloc 开辟空间 C语言也提供了另外一个开辟空间的函数,calloc 与 malloc 不同的是,calloc 开辟空间之后,在返回空间的起始地址之前,把所有空间全部赋值为 0 。示例:
//C语言文档给的代码 void* calloc (void* ptr, size_t size);

int main() { int* p = (int*)calloc(10, sizeof(int)); if (NULL != p) {//使用空间 } free(p); p = NULL; return 0; }

C语言|空间用多少我说了算! C语言动态内存!
文章图片

C语言|空间用多少我说了算! C语言动态内存!
文章图片

由第二张图片就可以看到,p 所指向的空间,全部被置为了 0 。如果我们对申请的内存有初始化的需求,就可以使用 calloc 来进行初始化。
realloc 管理内存 有时候我们会发现申请的内存大了或者小了,所以就用到 realloc 来对内存大小进行灵活的调整。如果 realloc 调整内存失败后,也会返回空指针。C语言给的函数模型是这样:
void* realloc (void* ptr, size_t size);

ptr 是要调整的内存地址。
size 是要调整的大小。
返回值是调整大小之后的内存起始位置。
realloc 调整内存的两种情况 情况1:原有空间之后有足够大的空间
【C语言|空间用多少我说了算! C语言动态内存!】当原来的空间后面有足够大的空间的话,就连着原有空间继续开辟,就是下面图片这样的情况。就是原有内存之后直接追加空间,原来空间的数据不发生变化,并且返回值的地址还是原来的地址。
C语言|空间用多少我说了算! C语言动态内存!
文章图片

原有空间之后没有足够大的空间
当原来空间的后面没有足够大的空间的话,其扩展的方法就是:再找一块空间,可以放得下原有的空间的内容和新开辟的空间,并且返回新的内存地址。不过在传回新的地址之前。会把原来的那段空间 free 掉。不能用原来的指针去接收返回值,因为如果开辟失败,那么原来的指针也变成 NULL 了。就是下图这样:
C语言|空间用多少我说了算! C语言动态内存!
文章图片

realloc 使用代码示例
int main() { int* p = (int*)calloc(10, sizeof(int)); //空间不够 增加到 20个 int int* ptr = (int*)realloc(p, 20 * sizeof(int)); if (ptr != NULL) {p = ptr; } else {//ptr是空指针 返回-1 return -1; } //增容成功 for (int i = 10; i < 20; i++) {*(ptr + i) = i; } for (int i = 0; i < 20; i++) {printf("%d ", *(ptr + i)); } free(ptr); ptr = NULL; free(p); p = NULL; return 0; }

    推荐阅读