C语言中关于动态内存分配的详解

目录
  • 一、malloc 与free函数
  • 二、calloc
  • 三、realloc
  • 四、常见的动态内存的错误

【C语言】动态内存分配

本期,我们将讲解malloc、calloc、realloc以及free函数。

这是个动态内存分配函数的头文件都是 <stdlib.h>。

c语言中动态分配内存的函数,可能有些初学c语言的人不免要问了:我们为什么要通过函数来实现动态分配内存呢?

首先让我们熟悉一下计算机的内存吧!在计算机的系统中大致有这四个内存区域:

1)栈:在栈里面储存一些我们定义的局部变量以及形参(形式参数);

2)字符常量区:主要是储存一些字符常量,比如:char *p=”hello world”;其中”hello world”就储存在字符常量区里面;

3)全局区:在全局区里储存一些全局变量和静态变量;

堆:堆主要是通过动态分配的储存空间,也就是我们接下需要讲的动态分配内存空间。

静态内存和动态内存的比较:

  • 静态内存是有系统自动分配,由系统自动释放。 静态内存是在栈分配的。(例如:函数里的局部变量)
  • 动态内存是由程序员手动分配,手动释放。 动态内存是在堆分配的。(例如:用C语言写链表时,需要自己对Node结点分配内存空间)

一、malloc 与free函数

void* **malloc( size_t ** size);

返回类型: void*,也就是说这个函数的可以返回所有类型的指针形式。只需要在开辟空间的时候进行强制类型转换一下即可。

函数参数:size_t size, 这个参数就是告诉这个函数,你需要开辟多少个字节的内存空间。

void free(void* memblock) ;

没有返回参数。

函数参数:void* memblock, free函数可以接收来自所有类型指针的 动态分配 的 内存空间。

一切以栗子来描述吧:

#include <stdlib.h>
#include <stdio.h>
int main()
{
    //开辟10个int类型的空间
    int* arr = (int*)malloc(10 * sizeof(int)); //切记这里给的大小,是10  *  int(4个字节)
    int i = 0;
    if (arr == NULL)
    {
        perror("malloc"); //有可能,malloc开辟空间失败,则malloc会返回NULL
        return 1;
    }

    for (i = 0; i < 10; i++)
        *(arr + i) = i; //放入数据 0 …… 9

    for (i = 0; i < 10; i++)
        printf("%d ",*(arr + i));

    //记得释放所开辟的空间
    free(arr);
    return 0;
}

二、calloc

void* calloc (size_t num, size_t** size );

返回类型:与malloc函数是一样的,就不在多说了。

函数参数:size_t num, 需要开辟多少个元素的空间。

​ size_ size, 每一个元素,所占用的内存空间是多少个字节。

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

栗子:

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

int main()
{
    //还是申请10个int类型的内存空间
    int* arr = (int*)calloc(10, sizeof(int));
    if (arr == NULL)
    {
        perror("calloc"); //calloc开辟空间的话,会返回NULL
        return 1;
    }

    //不做赋值运算,直接输出刚开辟的空间,看是否是已经初始化为0了
    int i = 0;
    for (i = 0; i < 10; i++)
        printf("%d ",*(arr + i));

    //记得释放空间
    free(arr);
    return 0;
}

三、realloc

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

作用: Reallocate memory blocks.(重新分配内存块)

  • memblock是需要调整的内存地址
  • size调整之后新大小
  • 返回值为调整之后的内存起始位置。
  • 这个函数调整原内存空间大小的基础_上,还会将原来内存中的数据移动到新的空间。
  • realloc在调整内存空间的是存在两种情况:

​ 情况1 :原有空间之后有足够大的空间

假设我还想为“红色框内的内存空间,扩大一倍,并且在这块空间的后面,是有足够的空间。所有realloc函数会在这紧挨这红色框后面直接开辟空间。并且返回的还是红色框的首元素地址。

情况2: 原有空间之后没有足够大的空间

此时,如果我还想为红色框的内存空间进行扩大,此时红色框后面紧挨着的空间已经被其他程序所占用了,此时想开辟空间的话,只能将现在这块空间先释放掉(realloc会自动释放),再去其他大一点的地方进行开辟空间。

如图:

注:realloc函数,有一个很值得注意的地方,看如下代码:

int main()
{
    int* arr = (int*)malloc(5 * sizeof(int)); //先开辟5个int类型的空间
    if (arr == NULL)
        return 1;

    //此时,我觉得malloc开辟的空间小了,我想增加
    arr = (int*) realloc(arr, 10);

    free(arr);
    return 0;
}

大家觉得,这段代码,有什么弊端?

分析:

在第8行,realloc函数,去调整arr的空间。他是先查看arr后面的内存空间是否够用,如果不够用的话,会去寻找其他大一点的地方去开辟空间。假设此时我的内存已经满了,此时realloc返回的是NULL。

也就是说,我本来想增容,结果没增成功,还把以前空间里的数据弄丢了。

所以在使用realloc函数时,先使用一个临时变量进行保存一下,如果返回不是NULL,我们在把返回的内存地址赋值给arr即可。

如下:

int main()
{
    int* arr = (int*)malloc(5 * sizeof(int)); //先开辟5个int类型的空间
    if (arr == NULL)
        return 1;

    //此时,我觉得malloc开辟的空间小了,我想增加
    int* tmp = NULL;
    tmp = (int*) realloc(arr, 10);
    if (tmp != NULL)
        arr = tmp;

    free(arr);
    return 0;
}

四、常见的动态内存的错误

  • 对NULL进行解引用操作
int main()
{
    int* arr = (int*)malloc(10 * sizeof(int));
    *arr = 10; //没有对arr进行NULL的判断
    free(arr);
    return 0;
}
  • 对非动态内存分配的空间进行free释放
int main()
{
    int a = 10;
    int* pa = &a;
    free(pa); //pa指针,并不是malloc等函数开辟的空间,不能使用free释放,系统会自动回收的
    return 0;
}
  • 使用free函数释放一块动态分配空间的一部分
int main()
{
    int* arr = (int*)malloc(10 * sizeof(int));
    if (arr == NULL)
        return 1;
    arr++; //此时,arr向后跳了4个字节
    free(arr); //现在再去释放空间,最前面的4个字节的空间就没有释放到,会报错
    return 0;
}
  • 对同一块内存空间进行多次释放
int main()
{
    int* arr = (int*)malloc(10 * sizeof(int));
    if (arr == NULL)
        return 1;

    free(arr);
    free(arr); //重复释放了
    return 0;
}
  • 动态开辟的空间忘记释放(内存泄漏)
int main()
{
    int* arr = (int*)malloc(10 * sizeof(int));
    if (arr == NULL)
        return 1;

    //没有释放空间,会造成内存泄漏
    //造成内存泄漏,有很多原因,例如,在调用其他函数时,想传回到本函数,指针没用正确,导致开辟的空间没有传回来等等
    return 0;
}

注: 动态开辟的内存空间,切记 一定要释放。不然后果很严重的!!!

本期更新就完啦!!!我们下期见啦

main()
{
int* arr = (int*)malloc(10 * sizeof(int));
if (arr == NULL)
return 1;

}

  //没有释放空间,会造成内存泄漏
  //造成内存泄漏,有很多原因,例如,在调用其他函数时,想传回到本函数,指针没用正确,导致开辟的空间没有传回来等等
  return 0;

注: 动态开辟的内存空间,切记 一定要释放。不然后果很严重的!!!

本期更新就完啦!!!我们下期见啦

到此这篇关于C语言中关于动态内存分配的详解的文章就介绍到这了,更多相关C语言 动态内存分配内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言动态内存分配函数的实现

    在C中我们开辟内存空间有两种方式 : 1.静态开辟内存 :例如: int a;int b[10]; 这种开辟内存空间的特点是 所开辟的内存是在栈中开辟的固定大小的 ,如a是4字节 ,数组b是40字节 ,并且数组在申明时必须指定其长度 , 如果是全局数组的话,内存是在编译时分配好的,如果是局部变量数组的话,运行时在栈上静态分配内存.不管是全局数组还是局部数组,它们都有一个特点,那就是数组大小是确定的,是代码中写死的.那如果我们想在程序运行时才确定一个数组的大小 , 前两种在栈上分配内存的方法显然是

  • C语言 动态内存分配详解

    C语言 动态内存分配详解 动态内存分配涉及到堆栈的概念:堆栈是两种数据结构.堆栈都是数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除. 栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. 堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表. \在C语言中,全局变量分配在内存中的静态存储区,非静态的局部变量(包括形参)是分配在内存的动态存储区,该存储区被

  • C语言动态内存分配的详解

    C语言动态内存分配的详解 1.为什么使用动态内存分配 数组在使用的时候可能造成内存浪费,使用动态内存分配可以解决这个问题. 2. malloc和free C函数库提供了两个函数,malloc和free,分别用于执行动态内存分配和释放. (1)void *malloc(size_t size); malloc的参数就是需要分配的内存字节数.malloc分配一块连续的内存.如果操作系统无法向malloc提供更多的内存,malloc就返回一个NULL指针. (2)void free(void *poi

  • c语言动态内存分配知识点及实例

    c语言怎么实现动态内存分配 我们经常会预先给程序开辟好内存空间,然后进行操作. int arr[5] ; 对这个数组我们在定义的时候必须给提前开辟好空间,并且在程序执行的过程中,这个开辟的内存空间是一直存在的,除非等到这个函数执行完毕,才会将空间释放.有个问题就是这个数组在程序中无法被修改. 这些问题给我们造成了一些使用上的不方便,所以,C中提供了malloc()函数. 关于malloc()函数,这个函数它接受一个参数:就是所需的内存的字节数.然后malloc()找到可用内存中那一个大小适合的块

  • C语言中关于动态内存分配的详解

    目录 一.malloc 与free函数 二.calloc 三.realloc 四.常见的动态内存的错误 [C语言]动态内存分配 本期,我们将讲解malloc.calloc.realloc以及free函数. 这是个动态内存分配函数的头文件都是 <stdlib.h>. c语言中动态分配内存的函数,可能有些初学c语言的人不免要问了:我们为什么要通过函数来实现动态分配内存呢? 首先让我们熟悉一下计算机的内存吧!在计算机的系统中大致有这四个内存区域: 1)栈:在栈里面储存一些我们定义的局部变量以及形参(

  • 深入了解C语言中的动态内存分配

    目录 什么是动态内存分配 如何进行动态内存分配 首先我要介绍两个函数 malloc 和 free 第二个开辟空间的动态内存分配的函数 calloc 大小修改函数realloc 今天我们来学习一下C语言中的动态内存分配 开始学习吧 什么是动态内存分配 我们目前已经知道的内存开辟的方式有: int val = 20;//在栈上开辟四个字节. char arr[10] = { 0 };//在栈上开辟十个字节的连续空间 但是上述空间的开辟方式有两个特点: 1.空间开辟的大小是固定的 2.数组在申明的时候

  • C++ 中继承与动态内存分配的详解

    C++ 中继承与动态内存分配的详解 继承是怎样与动态内存分配进行互动的呢?例如,如果基类使用动态内存分配,并重新定义赋值和复制构造函数,这将怎样影响派生类的实现呢?这个问题的答案取决于派生类的属性.如果派生类也使用动态内存分配,那么就需要学习几个新的小技巧.下面来看看这两种情况: 一.派生类不使用new 派生类是否需要为显示定义析构函数,复制构造函数和赋值操作符呢? 不需要! 首先,来看是否需要析构函数,如果没有定义析构函数,编译器将定义一个不执行任何操作的默认构造函数.实际上,派生类的默认构造

  • C语言 动态内存分配的详解及实例

    1. 动态内存分配的意义 (1)C 语言中的一切操作都是基于内存的. (2)变量和数组都是内存的别名. ①内存分配由编译器在编译期间决定 ②定义数组的时候必须指定数组长度 ③数组长度是在编译期就必须确定的 (3)但是程序运行的过程中,可能需要使用一些额外的内存空间 2. malloc 和 free 函数 (1)malloc 和 free 用于执行动态内存分配的释放 (2)malloc 所分配的是一块连续的内存 (3)malloc 以字节为单位,并且返回值不带任何的类型信息:void* mallo

  • C语言的动态内存分配及动态内存分配函数详解

    目录 malloc malloc的使用: free calloc calloc的使用: realloc realloc的使用改进: realloc的另一种用法: 常见的动态内存错误 对空指针的解引用操作 对动态开辟空间的越界访问 对非动态开辟内存使用free释放 使用free释放一块动态开辟内存的一部分 对同一块动态内存多次释放 动态开辟内存忘记释放(内存泄露) 找出下面问题: T1: T2: T3: T4: 柔性数组 柔性数组的定义 柔性数组的特点: 总结 malloc void *mallo

  • C语言编程C++动态内存分配示例讲解

    目录 动态内存管理 为什么存在动态内存分配 动态内存函数的介绍 malloc申请空间和free释放空间 有借有还 free释放内存 calloc申请内存 realloc调整动态内存的大小 realloc使用的注意事项 当然realloc也可以直接开辟空间 常见的动态内存错误 1.对NULL指针的解引用操作 2.对动态开辟空间的越界访问 3.对非动态开辟内存使用free释放 4.使用free释放一块动态内存开辟的一部分 5.对同一块动态内存多次释放 6.动态开辟内存忘记释放(内存泄漏) 几个面试题

  • C语言深入探索动态内存分配的使用

    目录 一.动态内存分配的意义 二.malloc 和 free 三.关于 malloc(0) 四.calloc 和 realloc 五.小结 一.动态内存分配的意义 C语言中的一切操作都是基于内存的 变量和数组都是内存的别名 内存分配由编译器在编译期间决定 定义数组的时候必须指定数组长度 数组长度是在编译期就必须确定的 需求:程序运行的过程中,可能需要使用一些额外的内存空间 二.malloc 和 free malloc 和 free 用于执行动态内存分配和释放 malloc 所分配的是一块连续的内

  • C语言深入讲解动态内存分配函数的使用

    目录 一.malloc 二.free(用于释放动态开辟的空间) 三.calloc 四.realloc 五.常见的动态内存分配错误 六.柔性数组 局部变量和函数的形参向栈区申请空间 全局变量和static静态变量向静态区申请空间 动态内存分配向堆区申请空间(位于<stdlib.h>或<cstdlib>头文件) 一.malloc void* malloc (size_t size); 分配内存块 分配一个连续可用的字节内存块,返回指向该内存块开头的指针. 新分配的内存块的内容未初始化,

  • 详解C语言中的动态内存管理

    目录 一.动态内存管理 1.1为什么要有动态内存管理 1.2动态内存介绍 1.3常见的动态内存错误 一.动态内存管理 1.1为什么要有动态内存管理 1.1.1  在c语言中我们普通的内存开辟是直接在栈上进行开辟的 int i = 20;//在栈空间上开辟四个字节 int arr[10]={0}; //在栈中连续开辟四十个字节 这样开辟的特点是: (1)他所开辟的空间是固定的 (2)数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配 但对于空间的需求,我们有的时候并不知道,有可能空间

随机推荐