动态内存分配函数——malloc、calloc、relloc

目录

1、malloc()和free()

2、calloc()函数

3、realloc()函数

4、动态内存分配和变长数组

5、动态内存分配


首先,回顾一下内存分配。所有程序都必须预留足够的内存来存储程序使用的数据。这些内存中有些是自动分配的:

float x;
int place[100];

这些声明预留了足够的空间,还为内存提供了一个标识符,可以使用x或place识别数据。

1、malloc()和free()

malloc()函数接受一个参数,所需的内存字节数。malloc()函数会找到合适的空闲内存块分配内存。这样的内存是匿名的,malloc()分配内存,到那时不会为其赋名。它返回动态内存分配内存块的首字节地址。因此,可以把该地址赋给一个指针变量,并使用指针访问这块内存。因为char表示1字节,malloc()的返回类型通常被定义为指向char的指针。从ANSI C标准开始,C使用一个新的类型:指向void的指针。该类型相当于一个“通用指针”。malloc()函数可用于返回指向数组的指针、指向结构的指针等,所以通常该函数的返回值会被强制转化为匹配的类型。然而,把指向void的指针赋给任意类型的指针完全不用考虑类型匹配的问题。如果 malloc()分配内存失败,将返回空指针。

我们试着用malloc()创建一个数组。除了用malloc在陈鼓型运行时请求一块内存,还需要一个指针记录着块内存的位置。例如,考虑下面的代码:

double * pt;
pt = (double *) malloc(30 * sizeof(double));

以上代码为30个double类型的值请求内存空间,并设置pt指向该位置。注意,指针pt被声明为指向一个double类型,而不是指向内涵30个double类型值的块。  回忆一下,数组名是该数组首元素的地址。因此,如果让pt指向这个块的首元素,便可像使用数组名一样使用它。也就是说,可以使用表达式pt[0]访问该块的首元素,pt[1]访问第2个元素.

现在,我们有3种创建数组的方法。

  • 声明数组时,用常量表达式表示数组的维度,用数组名访问数组的元素。可以用静态内存或自动内存创建这种数组。
  • 声明变长数组(C99)时,用变量表达式表设计数组的维度,用数组名访问数组的元素。具有这种特性的数组只能在自动内存中创建。
  • 声明一个指针,调用malloc(),将其返回值赋给指针,使用指针访问数组的元素。该指针可以是静态的或自动的。

 使用第2种和第3种方法可以创建动态数组,可以在程序运行时选择数组的大小和分配内存。

通常,malloc()要与free()配套使用。free()函数的参数是之前 malloc()返回的地址,应该是一个指针,指向由 malloc()分配的一块内存。该函数释放之前 malloc()分配的内存。动态分配内存的存储期从调用 malloc()分配内存到调用 free()释放内存为止。malloc()和 free()的原型都在 stdlib.h 头文件中。

使用 malloc(),程序可以在运行时才确定数组的大小。调用 exit ( ) 函 数 结 束 程 序 , 其 原 型 在 stdlib.h 中 。EXIT_SUCCESS 表示普通的程序结束,EXIT_FAILURE 表示程序异常中止。EXIT_FAILURE也被定义在stdlib.h中。

注意,free()函数位于程序的末尾,它释放了malloc()函数分配的内存,free()函数只释放其参数指向的内存块。

描述:

C 库函数 void *malloc(size_t size) 分配所需的内存空间,并返回一个指向它的指针。

声明:

void *malloc(size_t size)

 参数:

  • size -- 内存块的大小,以字节为单位。

返回值:

该函数返回一个指针 ,指向已分配大小的内存。如果请求失败,则返回 NULL。 

用法:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *array = (int*)malloc(10 * sizeof(int)); // 分配10个整数的内存
    if (array == NULL) {
        fprintf(stderr, "内存分配失败\n");
        return 1;
    }

    // 初始化内存
    for (int i = 0; i < 10; ++i) {
        array[i] = i;
    }

    // 使用内存
    for (int i = 0; i < 10; ++i) {
        printf("%d ", array[i]);
    }
    printf("\n");

    // 释放内存
    free(array);

    return 0;
}

 

 free函数

描述:

C 库函数 void free(void *ptr) 释放之前调用 calloc、malloc 或 realloc 所分配的内存空间。

声明:

void free(void *ptr)

参数:

ptr -- 指针指向一个要释放内存的内存块,该内存块之前是通过调用 malloc、calloc 或 realloc 进行分配内存的。如果传递的参数是一个空指针,则不会执行任何动作。

返回值:

该函数不返回任何值。

2、calloc()函数

分配内存还可以使用calloc()函数,典型的用法如下:

long * newmem;
newmem = (long *)calloc(100, sizeof(long));

和malloc()类似,在 ANSI 之前,calloc()也指向 char 的指针;在 ANSI 之后,返回指向 void 的指针。如果要存储不同的类型,应用强制类型转换运算符。calloc()函数接受两个无符号整数作为参数(ANSI 规定是 size_t 类型)。第一个参数是所需的存储单元数量,第二个参数是存储单元的大小。

calloc()函数还有一个特性,它把块中的所有位都设置为0(注意,在某些硬件系统中,不是把所有位都设置为0来表示浮点值0)。free()函数也可用于释放calloc()分配的内存。

描述:

C 库函数 void *calloc(size_t nitems, size_t size) 分配所需的内存空间,并返回一个指向它的指针。malloccalloc 之间的不同点是,malloc 不会设置内存为零,而 calloc 会设置分配的内存为零。

注意:calloc() 函数将分配的内存全部初始化为零。如果不需要初始化,可以使用 malloc() 函数代替。另外,使用 calloc() 函数时需要注意,如果分配的内存块过大,可能会导致内存不足的问题。

声明:

void *calloc(size_t nitems, size_t size)

参数:

  • nitems -- 要被分配的元素个数。
  • size -- 元素的大小。

返回值:

该函数返回一个指针,指向已分配的内存。如果请求失败,则返回 NULL。

用法:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *array = calloc(10, sizeof(int)); // 分配10个整数的内存,并将其初始化为0
    if (array == NULL) {
        fprintf(stderr, "内存分配失败\n");
        return 1;
    }

    // 使用内存
    for (int i = 0; i < 10; ++i) {
        printf("%d ", array[i]);
    }
    printf("\n");

    // 释放内存
    free(array);

    return 0;
}

 

3、realloc()函数

描述:

C 库函数 void *realloc(void *ptr, size_t size) 尝试重新调整之前调用 malloccalloc 所分配的 ptr 所指向的内存块的大小。

声明:

void *realloc(void *ptr, size_t size)

参数:

  • ptr -- 指针指向一个要重新分配内存的内存块,该内存块之前是通过调用 malloc、calloc 或 realloc 进行分配内存的。如果为空指针,则会分配一个新的内存块,且函数返回一个指向它的指针。
  • size -- 内存块的新的大小,以字节为单位。如果大小为 0,且 ptr 指向一个已存在的内存块,则 ptr 所指向的内存块会被释放,并返回一个空指针。

 

realloc 函数的行为取决于 ptr 参数和 size 参数的值:

  1. 如果 ptrNULL,那么 realloc 行为与 malloc 相同,分配一个大小为 size 的新内存块,并返回指向这个新内存块的指针。
  2. 如果 size0,并且 ptr 指向的是一个非 NULL 的内存块,那么 realloc 会释放这个内存块,并返回 NULL
  3. 如果 size0,并且 ptrNULL,那么 realloc 会返回 NULL
  4. 如果 size 大于 ptr 指向的内存块的大小,realloc 会分配一个更大的内存块,将原内存块的内容复制到新块中,并释放原内存块。返回值是新内存块的指针。
  5. 如果 size 小于 ptr 指向的内存块的大小,realloc 可能会调整内存块的大小,但不会移动内存块中的内容。返回值是原内存块的指针。

返回值:

该函数返回一个指针 ,指向重新分配大小的内存。如果请求失败,则返回 NULL。

用法:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *ptr = (int *)malloc(10 * sizeof(int)); // 分配足够存放10个整数的内存
    if (ptr == NULL) {
        fprintf(stderr, "内存分配失败\n");
        return 1;
    }

    // 初始化内存
    for (int i = 0; i < 10; ++i) {
        ptr[i] = i;
    }

    // 打印原始内存内容
    for (int i = 0; i < 10; ++i) {
        printf("%d ", ptr[i]);
    }
    printf("\n");

    // 重新分配内存,扩大到20个整数的大小
    ptr = realloc(ptr, 20 * sizeof(int));
    if (ptr == NULL) {
        fprintf(stderr, "内存重新分配失败\n");
        return 1;
    }

    // 打印重新分配后的内存内容
    for (int i = 0; i < 20; ++i) {
        printf("%d ", ptr[i]);
    }
    printf("\n");

    // 释放内存
    free(ptr);

    return 0;
}

 

4、动态内存分配和变长数组

变长数组(VLA)和调用malloc()在功能上有些重合。不同的是,变长数组是自动存储类型,因此,程序在离开变长数组定义的所在块时,变长数组占用的内存空间会被自动释放,不必使用free()。另一方面,用malloc()创建的数组不必局限在一个函数内访问。  例如,可以这样做:被调函数创建一个数组并返回指针,供主调函数访问,然后主调函数在末尾调用free()释放之前别函数分配的内存。 另外,free()所用的指针变量可以与malloc()的指针变量不i同,但是两个指针必须存储相同的地址。

5、动态内存分配

一般可以认为程序把它可用的内存分为3部分: 一部分供具有外部链接、内部链接和无链接的静态变量使用;一部分供自动变量使用;一部分供动态内存分配。

动态内存分配在调用malloc()或相关函数时存在,在调用free()后释放。这部分内存由程序员管理,而不是一套规则。所以内存块可以在一个函数中创建,在另一个函数中销毁。

总而言之,程序把静态对象、自动对象和动态分配对象存储在不同的区域。

  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值