c语言详解动态内存分配及常见错误的解决

目录
  • 为什么会有动态内存分配
  • 动态内存函数的介绍
    • malloc
    • free
    • calloc
    • realloc
  • 常见的错误
    • 对NULL指针的解引用操作
    • 越界访问
    • 对非动态内存进行free
    • 使用free释放动态开辟内存的一部分
    • 对同一块动态内存多次释放
    • 对动态内存内存忘记释放(内存泄漏)

为什么会有动态内存分配

内存使用方式有两种

1.创建一个变量

2.创建一个数组

int a = 1;
int arr[10];

但是这两种方式都有一些特点

1.空间是固定大小的,不会变

2.必须提前知道要开辟多少空间,必须指定数组的长度。

但是实际上,对于空间的需求,有些时候,我们并不知道要分配多少内存空间,有时候需要在程序运行时才知道,比如用一个数组存放班级学生的年龄,我们不知道有多少个学生,不知道需要多大的空间,而且编译器又不支持变长的数组,应该是常量表达式。这时候,用数组分配固定的空间就不适合了。

为了更好地分配内存空间,这时候就需要我们的动态内存分配了。

说到内存,我们知道内存分为3个区域,栈区,堆区,静态区。

栈区——局部变量,函数形参

堆区——动态内存分配

静态区——全局变量,静态变量(如static int a = 10)

动态内存函数的介绍

malloc

void *malloc( size_t size );

函数向堆区开辟一块连续的空间,返回空间的起始地址。

  • 开辟成功,返回一个开辟好的空间的指针
  • 开辟失败,返回NULL指针,所以要检查是否开辟成功
  • 返回的类型是void*,所以malloc并不知道开辟的类型,自己决定
  • 如果size为0,malloc的行为是标准未定义的,取决于编译器
  • 记得引用头文件#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
    int* p = (int*)malloc(10 * sizeof(int));
    if (p == NULL)
    {
        //打印错误原因的一个方式
        printf("%s\n", strerror(errno));
    }
    else
    {
        //正常使用
        int i = 0;
        for (i = 0; i < 10; i++)
        {
            *(p + i) = i;
        }
        for (i = 0; i < 10; i++)
        {
            printf("%d ", *(p+i));
        }
    }
    //释放
    free(p);
    p = NULL;
    return 0;
}

free

void free( void *memblock );

c语言提供一个函数free,专门用来动态内存的回收和释放的

头文件是#include <stdlib.h>

注意几点:

用于动态开辟的内存,如果不是的话,那free函数行为是未定义的

如果指针是NULL指针,则函数什么事都不做

被free后的指针最好手动置为NULL,避免野指针,造成错误

free(p);
p=NULL;

calloc

void *calloc( size_t num, size_t size );

calloc也是用来动态开辟空间。头文件也为#include <stdlib.h>

与malloc的区别:

参数不同

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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
    //malloc(10*sizeof(int));
    int*p = (int*)calloc(10, sizeof(int));
    if (p == NULL)
    {
        printf("%s\n", strerror(errno));
    }
    else
    {
        int i = 0;
        for (i = 0; i < 10; i++)
        {
            printf("%d ", *(p + i));
        }
    }
    free(p);
    p = NULL;
    return 0;
}

调试一下,可以看到内存都初始化为0了

根据实际情况,如果需要初始化的话那就使用calloc

realloc

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

头文件也是引用#include <stdlib.h>

ptr是要调整的内存地址

size调整之后新大小,而不是增加的大小

返回值为调整之后的内存起始位置

realloc函数的出现让动态内存管理更加灵活

有时候我们发现申请的空间太小,有时候又会觉得申请过大了,为了合理的分配内存,我们可以对内存的大小做灵活的调整,realloc可以做到对动态内存大小的调整

注意事项

realloc在调整内存存在两种情况

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

  • 如果p指向的空间之后有足够的内存可以追加,则直接追加,后返回p

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

  • 如果p指向的空间之后没有足够的内存空间可以追加,则realloc函数会重新找一个新的内存区域开辟一块满足需求的空间,并且把原来内存中的数据拷贝回来,释放旧的内存空间,最后返回新开辟的内存空间地址
  • 得用一个新的变量来接收realloc的返回值

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
    int* p = (int*)malloc(20);
    if (p == NULL)
    {
        printf("%s\n", strerror(errno));
    }
    else
    {
        int i = 0;
        for (i = 0; i < 5; i++)
        {
            *(p + i) = i;
        }
    }
    //在使用malloc开辟的20个空间
    //假设这里20个字节不能满足我们的使用
    //希望我们能有40个字节的空间
    //这里就可以使用realloc来调整动态开辟的内存
    int* ptr = realloc(p, 40);
    if (ptr != NULL)
    {
        p = ptr;
        int i = 0;
        for (i = 5; i < 10; i++)
        {
            *(p + i) = i;
        }
        for (i = 0; i < 10; i++)
        {
            printf("%d ", *(p+ i));
        }
    }
    free(p);
    p = NULL;
    return 0;
}

常见的错误

对NULL指针的解引用操作

int main()
{
    int* p = (int*)malloc(INT_MAX/4);
    *p = 20;//如果p是空指针,就会有问题;
    free(p);
    return 0;
}

越界访问

int* p = (int*)malloc(40);
    if (p == NULL)
    {
        return 0;
    }
    int i = 0;
    //越界
    for (i = 0; i <= 10; i++)
    {
        *(p + i) = i;
    }
    free(p);
    p = NULL;

应该是i<10

对非动态内存进行free

 int a = 10;
    int* p = &a;
    free(p);
    p = NULL;

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

int* p = (int*)malloc(40);
    if (p == NULL)
    {
        return 0;
    }
    int i = 0;
    for (i = 0; i < 10; i++)
    {
        *p++ = i;
    }
    free(p);
    return 0;

p不在指向动态内存开辟的起始位置,我们应该重新定义一个指针来记住起始地址

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

int* p = (int*)malloc(40);
    if (p == NULL)
    {
        return 0;
    }
    free(p);
    free(p);

对动态内存内存忘记释放(内存泄漏)

忘记释放动态开辟的内存,就会造成内存泄漏

 while (1)
    {
        malloc(1);
        Sleep(1000);
    }

申请内存而不还,计算机的内存是有限的,内存将会被耗干

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

(0)

相关推荐

  • C语言中动态内存分配malloc、calloc和realloc函数解析

    目录 前言 free函数 malloc函数 calloc函数 realloc函数 扩充 malloc/calloc/realloc区别总结 总结 前言 有时候我们需要的空间大小不确定,需要随着程序需要的空间而变化, 那以数组开辟的固定大小的空间就不适用了, 这时候我们就需要动态分配开辟空间了.当空间不够时就扩容.动态开辟是在堆区开辟一块连续可用空间,并返回这块空间的地址.有三种函数malloc, calloc和realloc.我们动态内存分配就在堆区开辟空间 上面的四个区只有堆区的空间是需要手动

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

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

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

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

  • c语言详解动态内存分配及常见错误的解决

    目录 为什么会有动态内存分配 动态内存函数的介绍 malloc free calloc realloc 常见的错误 对NULL指针的解引用操作 越界访问 对非动态内存进行free 使用free释放动态开辟内存的一部分 对同一块动态内存多次释放 对动态内存内存忘记释放(内存泄漏) 为什么会有动态内存分配 内存使用方式有两种 1.创建一个变量 2.创建一个数组 int a = 1; int arr[10]; 但是这两种方式都有一些特点 1.空间是固定大小的,不会变 2.必须提前知道要开辟多少空间,必

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • C语言编程之动态内存与柔性数组的了解

    目录 介绍动态内存分配函数 常见的动态内存开辟的错误 举个例子 柔性数组 柔性数组的特点 创建变量 1,局部变量–栈区 2,全局变量–静态区 创建数组 1,局部数组–栈区 2,全局数组–静态区 介绍动态内存分配函数 malloc free calloc realloc 所有的动态内存分配,都是在堆中进行分配 分别介绍动态内存函数 malloc void* malloc(size_t size) 向内存堆中申请size个字节,并返回该空间的首地址.同时定义一个指针来接受函数返回的地址. 如: in

  • 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

随机推荐