【C语言】动态内存分配:malloc、calloc、realloc

目录

一、动态内存函数的介绍 

二、常见的动态内存错误

三、柔性数组

四、内存分配


一、动态内存函数的介绍 

  • free

在C语言中,并没有直接的 "free" 关键字或函数来释放内存。然而,C语言提供了另一个与内存管理相关的函数,即 "free()" 函数,用于释放之前通过动态内存分配函数(例如 "malloc()" 或 "calloc()")分配的内存。

函数原型:

void free(void* ptr);

函数功能:
"free()" 函数用于释放先前分配的动态内存。它接受一个指向要释放的内存块的指针作为参数。

1、如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。

2、如果参数 ptr 是NULL指针,则函数什么事都不做。

需要注意的是,在使用 "free()" 函数释放内存后,应该避免再次引用该指针,因为该指针可能会指向无效的内存区域。此外,动态分配的内存应该在不再使用时及时释放,以避免内存泄漏问题。

  • malloc

malloc(Memory Allocate的缩写)是C语言中的一个库函数,用于动态分配内存空间。它位于stdlib.h头文件中,可以在程序运行时根据需要动态地为变量分配一块指定大小的内存空间。

malloc函数的原型如下:

void *malloc(size_t size);

参数size表示所需内存空间的大小,以字节为单位。返回值类型为void*,即指向分配内存的指针。如果分配内存失败,则返回NULL。

使用malloc函数进行内存分配时,需要注意以下几点:

  1. 需要包含stdlib.h头文件。
  2. 分配的内存空间是连续的字节块,可以按照字节进行读写操作。
  3. malloc函数分配的内存空间不会被初始化,可能包含任意数据,需要在使用之前进行合适的初始化。
  4. 使用完毕后,应该使用free函数释放已分配的内存,以避免内存泄漏。
  • calloc

在C语言中,calloc() 函数用于动态地分配内存,并将分配的内存块初始化为零。它是C标准库中的一部分,通常与 malloc() 函数一起用于内存管理。

以下是 calloc() 函数的基本介绍和使用方式:

函数原型:

void* calloc(size_t num, size_t size);

函数功能:
calloc() 函数用于分配一个大小为 num * size 字节的连续内存块,并将分配的内存初始化为零。

参数解释:

  • num:要分配的元素的数量。
  • size:每个元素的大小(以字节为单位)。

1、函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。

2、与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。

  • realloc

在C语言中,realloc() 函数用于重新分配先前通过 malloc()、calloc() 或 realloc() 分配的内存块的大小。它允许我们在运行时更改内存块的大小。

以下是 realloc() 函数的基本介绍和使用方式:

函数原型:

void* realloc(void* ptr, size_t size);

函数功能:
realloc() 函数用于重新分配已分配内存的大小。它接受一个指向先前分配的内存块的指针和新的大小作为参数,并返回重新分配内存后的指针。

  • ptr:指向先前分配的内存块的指针。
  • size:新的内存块大小(以字节为单位)。
  • 返回值为调整之后的内存起始位置。

有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时 候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小 的调整。

这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。

realloc在调整内存空间的是存在两种情况:

        情况1:原有空间之后有足够大的空间.在后面追加新空间,返回原来的地址

        情况2:原有空间之后没有足够大的空间:开辟新空间,将旧空间的数据拷贝到新空间,释放旧空间,返回新空间的起始地址

二、常见的动态内存错误

  • 对NULL指针的解引用操作

当一个指针被赋值为NULL,即空指针时,对其进行解引用操作会导致运行时错误。解引用操作意味着试图访问或修改指针所指向的内存地址上的值,但由于NULL指针并没有有效的内存地址,因此这样的操作将导致程序崩溃。 

  • 对动态开辟空间的越界访问

在使用malloc、calloc或realloc等函数动态分配内存时,需要注意确保在访问这些内存块时不要越界。如果尝试读取或写入超出分配内存范围的位置,将导致未定义的行为,可能会破坏其他内存区域或导致程序崩溃。

  • 对非动态开辟内存使用free释放

内存释放函数free()应该仅用于释放通过malloc、calloc或realloc等动态分配的内存。如果尝试使用free()释放栈上分配的内存、全局变量或静态变量等非动态开辟的内存块,将导致未定义的行为,可能会破坏程序的内存结构。

  • 使用free释放一块动态开辟内存的一部分

free()函数释放整个动态分配的内存块。如果试图释放这块内存的一部分,而不是整个内存块,将导致内存泄漏和未定义的行为。因此,必须确保在调用free()之前使用指针进行的任何操作都已完成,且不再需要该内存块。

  • 对同一块动态内存多次释放

如果对同一个指针多次调用free()函数,将导致内存错误和未定义的行为。每个动态分配的内存块应该只被释放一次。为了避免这个错误,可以在释放内存后将指针设置为NULL,以便在后续代码中发现并避免重复释放。

  • 动态开辟内存忘记释放(内存泄漏)

使用malloc、calloc或realloc等动态分配内存时,必须确保在不再使用这些内存块时释放它们。如果忘记释放内存,将导致内存泄漏,即分配的内存无法再次被回收和使用,最终可能导致系统内存不足的问题。

三、柔性数组

C语言的柔性数组(Flexible Array Member)是指结构体中的一个数组成员,该数组的长度可以在运行时确定,而不是在编译时确定。

柔性数组的使用场景通常是在结构体的末尾,用来表示可变长度的数据。它的语法形式为:

struct StructName {
    // 其他成员...
    Type flexArray[];
};

其中,Type表示数组元素的类型。

使用柔性数组时,需要注意以下几点:

  1. 柔性数组必须是结构体中的最后一个成员,因为它的长度是在运行时确定的,紧随其后的无法再有其他成员。
  2. 结构体中不能直接初始化柔性数组,应该通过动态内存分配来给柔性数组分配空间。
  3. 访问柔性数组的元素时要确保不超出实际分配的内存范围。

以下是一个使用柔性数组的示例:

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

struct Data {
    int length;
    int array[];  // 柔性数组
};

int main() {
    int len = 5;
    struct Data* data = malloc(sizeof(struct Data) + len * sizeof(int));

    data->length = len;
    for (int i = 0; i < len; i++) {
        data->array[i] = i;
    }

    for (int i = 0; i < len; i++) {
        printf("%d ", data->array[i]);
    }
    printf("
");

    free(data);
    return 0;
}

在上述示例中,我们定义了一个struct Data结构体,其中包含一个柔性数组array。我们通过动态内存分配的方式为柔性数组分配了内存空间,并使用这个柔性数组存储了一些数据。最后,记得释放动态分配的内存。

需要注意的是,柔性数组并不是C语言标准的一部分,它是一种常用的非标准扩展。因此,在使用柔性数组时要确保编译器和平台的兼容性。

四、内存分配

1. 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结 束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是 分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返 回地址等。

2. 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分 配方式类似于链表。

3. 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。

4. 代码段:存放函数体(类成员函数和全局函数)的二进制代码。 

   实际上普通的局部变量是在栈区分配空间的,栈区的特点是在上面创建的变量出了作用域就销毁。 但是被static修饰的变量存放在数据段(静态区),数据段的特点是在上面创建的变量,直到程序 结束才销毁 所以生命周期变长。

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无敌岩雀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值