【C语言进阶】动态内存管理(上)

简介: 【C语言进阶】动态内存管理(上)

1.为什么存在动态内存管理


       在我们之前的学习里,我们已经掌握了开辟内存的方式

int val = 20;//在栈空间开辟四个字节
char arr[10] = { 0 };//在栈空间上开辟10个字节的连续空间


但是上述的开辟空间的方式存在很大的局限性:

1.开辟的空间大小是固定的;

2.数组在申明的时候必须指定数组的长度,所需要的内存大小在编译时分配。


但是,对于空间的需求不止于此,有时候我们只有在程序运行起来以后才能知道所需空间大小,那数组的编译时开辟空间就不能满足了,因此我们引入了动态内存开辟的方法。


2.动态内存函数介绍


1.malloc

void*malloc(size_tsize);


malloc向内存申请一块连续可用的空间,并返回这块空间的指针。

  • 如果开辟成功,返回指向这块空间的指针
  • 如果开辟失败,返回NULL,因此使用malloc以后要做好检查
  • 返回值的类型是void*,使用前要强转
  • 如果参数size传的是0,这是C语言标准未定义的行为,由编译器决定

5da2fe5dcb84426cb321c3510b795093.png


2.calloc


c语言还提供了一个函数叫calloc,也用来动态内存分配

void*calloc(size_tnum,size_tsize);


是用来为开辟num个大小为size的空间,并且把空间内的每个字节初始化为0,与malloc的区别就是是否会初始化申请的内存空间。

119c0a38c1b44f57a2a3ed10eb14c11b.png


3.realloc


realloc函数的出现,让动态内存开辟更加灵活,有时候我们在使用动态开辟的空间,会发现空间小了或者大了。为了合理的使用内存,我们引入了realloc函数。


void*realloc(void*memblock,size_tsize);


  • 第一个参数是需要调整的内存地址
  • 第二个参数是调整后的新大小,
  • 返回值是调整后的内存的起始位置
  • realloc函数调整内存空间有两种情况
  • 情况一:原有空间之后有足够大的空间,此时realloc函数会在该空间后面直接追加空间,原有数据不受影响
  • 情况二:原有空间之后没有足够大的空间,此时realloc函数会再开辟一个足够大的空间,并将原有数据拷贝到新的空间,然后释放原有空间。

33867355382049a1b50f81b57ddfa07c.png


4.free


上述的三个动态内存开辟函数都是在堆区上开辟空间,那么空间使用后是需要释放的,否则就会造成内存泄漏,因此我们用free函数释放动态开辟的内存空间


void free( void *memblock );


  • 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
  • 如果参数 ptr 是NULL指针,则函数什么事都不做。


3.常见的动态内存错误


1.对NULL指针的解引用操作

void test()
{
    int *p = (int *)malloc(INT_MAX/4);
    *p = 20;//如果p的值是NULL,就会有问题
    free(p);
}


上面的代码没有检验是否开辟成功,判断p是否为空指针,直接解引用,如果p的值为NULL,就会有问题


2.对动态开辟空间越界访问

void test()
{
    int i = 0;
    int *p = (int *)malloc(10*sizeof(int));
    if(NULL == p)
    {
        exit(EXIT_FAILURE);
    }
    for(i=0; i<=10; i++)
    {
        *(p+i) = i;//当i是10的时候越界访问
    }
    free(p);
}


我们只开辟了10个整形空间,当i = 10的时候,会访问到11个整形空间,就会越界访问。


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

void test()
{
    int a = 10;
    int *p = &a;
    free(p);
}


变量a是在栈区开辟的,而动态内存是在堆区开辟的,因此变量a不能用free释放,这是未定义的行为。


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

void test()
{
    int *p = (int *)malloc(100);
    p++;
    free(p);//p不再指向动态内存的起始位置
}


此时,p已经不再指向动态开辟的内存的起始位置,不能用free释放。

相关文章
|
4天前
|
C语言
C语言—内存函数的实现和模拟实现(内存函数的丝绸之路)
C语言—内存函数的实现和模拟实现(内存函数的丝绸之路)
18 0
|
5天前
|
程序员 编译器 C语言
C语言----动态内存分配(malloc calloc relloc free)超全知识点
C语言----动态内存分配(malloc calloc relloc free)超全知识点
14 6
|
5天前
|
存储 程序员 编译器
C语言:动态内存管理
C语言:动态内存管理
11 1
|
5天前
|
存储 编译器 程序员
C语言:数据在内存中的存储
C语言:数据在内存中的存储
15 2
|
5天前
|
存储 编译器 C语言
C语言:字符函数 & 字符串函数 & 内存函数
C语言:字符函数 & 字符串函数 & 内存函数
16 2
|
5天前
|
存储 C语言 开发者
【C言专栏】C 语言实现动态内存分配
【4月更文挑战第30天】C语言中的动态内存分配允许程序运行时按需分配内存,提供处理未知数据量的灵活性。这涉及`malloc()`, `calloc()`, `realloc()`, 和 `free()`四个标准库函数。`malloc()`分配指定大小的内存,`calloc()`同时初始化为零,`realloc()`调整内存大小,而`free()`释放内存。开发者需谨慎处理内存泄漏和指针使用,确保程序的稳定性和性能。动态内存分配是C语言中的重要技能,但也需要良好的内存管理实践。
|
5天前
|
存储 C语言
C语言进阶---------作业复习
C语言进阶---------作业复习
|
5天前
|
存储 Linux C语言
C语言进阶第十一节 --------程序环境和预处理(包含宏的解释)-2
C语言进阶第十一节 --------程序环境和预处理(包含宏的解释)
|
5天前
|
自然语言处理 Linux 编译器
C语言进阶第十一节 --------程序环境和预处理(包含宏的解释)-1
C语言进阶第十一节 --------程序环境和预处理(包含宏的解释)
|
5天前
|
存储 编译器 C语言
C语言进阶第十课 --------文件的操作-1
C语言进阶第十课 --------文件的操作