深入探索C语言动态内存分配:释放你的程序潜力

news/2024/11/8 17:12:08/

PixPin_2024-03-20_23-59-58.png

🌈大家好!我是Kevin,蠢蠢大一幼崽,很高兴你们可以来阅读我的博客!
🌟我热衷于分享🖊学习经验,🏫多彩生活,精彩足球赛事⚽
🌟感谢大家的支持,期待我们共同进步💞
🔗我的CSDN个人主页: Kevin ’ s blog
📂专栏收录:C预言


动态内存分配的意义

假如我们创建一个存放一百个元素的数组:

char arr[100] = {0};

如果我们要用这个数组来存储数据的话只能存储100个char型的数据,如果再想要往数组内添加数据的话就会越界。

所以在这个时候有两种方法,第一个方法是再创建一个数组然后将两个数组拼接,第二个方法时用动态内存分配。动态内存分配的快捷,实用性和可操控要比第一种方法强很多,那么究竟强在哪里呢?在这篇博客中我将进行具体阐述。

动态内存分配相关函数

1. malloc

malloc函数用来向内存申请⼀块连续可⽤的空间,并返回指向这块空间的指针。

该函数原型如下:

void* malloc (size_t size);

可以看出,该函数的返回值是void*说明返回类型可以改变,传的参数size作用是向内存申请size大小的内存,用size_t类型可以不用担心申请的内存过大而不能完成申请。

对于开辟内存的结果和操作:

  • 如果开辟成功,则返回⼀个指向开辟好空间的指针。

  • 如果开辟失败,则返回⼀个 NULL 指针,因此malloc的返回值⼀定要做检查。

  • 返回值 的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使⽤的时候使⽤者⾃⼰来决定。

  • 如果参数 size 为0,malloc的⾏为是标准是未定义的,取决于编译器

2. free

free函数用来释放动态分配的内存(只能释放动态分配的内存),函数原型如下:

void free (void* ptr);
  • 如果参数 ptr 指向的空间不是动态开辟的,那free函数的⾏为是未定义的。

  • 如果参数 ptr 是NULL指针,则无事发生。

在了解到malloc和free函数后就可以利用这两个函数进行一个简单的实例代码:

#include <stdio.h>
#include <stdlib.h>
int main()
{int num = 0;scanf("%d", &num);int arr[num] = {0};int* ptr = NULL;ptr = (int*)malloc(num*sizeof(int));if(NULL != ptr)//判断ptr指针是否为空{int i = 0;for(i=0; i<num; i++){*(ptr+i) = 0}}free(ptr);//释放ptr所指向的动态内存ptr = NULL;//是否有必要?return 0;
}

该段代码就是实现动态分配,然后释放分配的空间。

3. calloc

calloc 函数也⽤来动态内存分配。原型如下:

void* calloc (size_t num, size_t size);
  • 函数的功能是为 num 个⼤⼩为 size 的元素开辟⼀块空间,并且把空间的每个字节初始化为0。

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

示例代码:

#include <stdio.h>
#include <stdlib.h>
int main()
{int* p = (int*)calloc(10, sizeof(int));if (NULL != p){int i = 0;for (i = 0; i < 10; i++){printf("%d ", *(p + i));}}free(p);p = NULL;return 0;
}

示例代码结果:

0 0 0 0 0 0 0 0 0 0

从函数的特性出发,如果我们对函数有初始化的需求的话可以直接使用 calloc 函数来进行内存空间的开辟,效果与 malloc 一样。

4. realloc

realloc 函数实现的是对原本开辟的空间进行调整大小,函数原型如下:

void* realloc (void* ptr, size_t size);  
  • ptr 是要调整的内存地址

  • size 调整之后新⼤⼩

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

  • 这个函数调整原内存空间⼤⼩的基础上,还会将原来内存中的数据移动(copy)到新的空间。

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

​ 情况1:原有空间之后有⾜够⼤的空间

​ 情况2:原有空间之后没有⾜够⼤的空间

以上所说两种空间是在内存上的空间,不是当前动态分配到的空间

4.1 原有空间足够大

当原有空间足够大时,我们要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发⽣变化。

4.2 原有空间不够

当原有的空间不够时,我们在堆空间上另找⼀个合适大小的连续空间来使⽤。这样函数返回的是⼀个新的内存地址。

realloc使用示例代码:

#include <stdlib.h>
int main()
{int* ptr = (int*)malloc(100);if (ptr != NULL){//业务处理}else{return 1;}//扩展容量//代码1 - 直接将realloc的返回值放到ptr中ptr = (int*)realloc(ptr, 1000);//这样可以吗?(如果申请失败会如何?)//代码2 - 先将realloc函数的返回值放在p中,不为NULL,在放ptr中int* p = NULL;p = realloc(ptr, 1000);if (p != NULL){ptr = p;}//业务处理free(ptr);return 0;
}

常见动态内存错误

1. 对NULL指针解引用

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

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);
}

3. 对⾮动态开辟内存使⽤free释放

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

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

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

5. **对同⼀块动态内存多次释放 **

void test()
{int* p = (int*)malloc(100);free(p);free(p);//重复释放
}

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

void test()
{int* p = (int*)malloc(100);if (NULL != p){*p = 20;}
}
int main()
{test();while (1);
}

结语

以上就是关于动态内存管理的博客内容。值得强调的是关于 free 掉内存这件事,一个程序如果不在不需要的时候free掉内存的话就会一直占用内存直到程序运行结束。

在我们平时的代码练习中不会有明显的影像,但是在大型程序中,如果内存一直占用,占用的内存不断增多,内存是有限的,不可能一直被占用,当内存爆满时程序就会出现问题了。

所以要注意关于内存空间的释放!


Black and White Gamer _Hacks or Reviews_ Gaming YouTube Video Intro.png


http://www.ppmy.cn/news/1394641.html

相关文章

【boost_search搜索引擎】1.获取数据源

boost搜索引擎 1、项目介绍2、获取数据源 1、项目介绍 boost_search项目和百度那种不一样&#xff0c;百度是全站搜索&#xff0c;而boost_search是一个站内搜索。而项目的宏观上实现思路就如同图上的思路。 2、获取数据源 我们要实现一个站内搜索&#xff0c;我们就要有这…

浅易理解:YoloV3 案例_05

目标 熟悉TFRecord文件的使用方法YoloV3模型结构及构建方法数据处理方法利用yoloV3模型进行训练和预测 1.TFrecord文件 该案例中我们依然使用VOC数据集来进行目标检测&#xff0c;不同的是我们要利用tfrecord文件来存储和读取数据&#xff0c;首先来看一下tfrecord文件的相关…

[AIGC] Redis基础命令集详细介绍

Redis是一个强大的开源的键-值存储系统&#xff0c;被广泛应用于各种应用程序中。在使用Redis时&#xff0c;我们需要掌握一些基本的Redis命令来操作存储在其上的数据。这篇文章将向你介绍一些基本的Redis命令&#xff0c;让你能够更好地使用和理解Redis。 文章目录 启动Redis…

yolov5/v7修改标签和检测框显示【最全】

1. 背景介绍 在计算机视觉领域&#xff0c;目标检测是一个重要的任务&#xff0c;它旨在识别图像中的对象并定位它们的边界框。近年来&#xff0c;基于深度学习的目标检测算法取得了显著的进展&#xff0c;其中YOLO&#xff08;You Only Look Once&#xff09;系列算法因其速度…

nodejs+vue分类信息服务平台移动端的设计与实现-安卓pythonflask-django-php

分类信息服务平台设计的目的是为用户提供活动信息、活动记录等方面的平台。 与PC端应用程序相比&#xff0c;分类信息服务平台的设计主要面向于移动端&#xff0c;旨在为管理员和用户、商铺提供一个分类信息服务平台。用户可以通过Android及时查看活动信息等。 分类信息服务平台…

pytorch 实现多层神经网络MLP(Pytorch 05)

一 多层感知机 最简单的深度网络称为多层感知机。多层感知机由 多层神经元 组成&#xff0c;每一层与它的上一层相连&#xff0c;从中接收输入&#xff1b;同时每一层也与它的下一层相连&#xff0c;影响当前层的神经元。 softmax 实现了 如何处理数据&#xff0c;如何将 输出…

【Godot 3.5控件】用TextureProgress制作血条

说明 本文写自2022年11月13日-14日&#xff0c;内容基于Godot3.5。后续可能会进行向4.2版本的转化。 概述 之前基于ProgressBar创建过血条组件。它主要是基于修改StyleBoxFlat&#xff0c;好处是它几乎可以算是矢量的&#xff0c;体积小&#xff0c;所有东西都是样式信息&am…

linux netstat-显示系统网络连接、路由表、接口统计、masquerade 连接等信息

linux 命令汇总 命令描述地址linux top实时查看系统性能linux top-linux 内存linux tar gz解压命令linux tar gz 解压命令linux tail显示文件末尾内容linux tail, linux headlinux rm删除文件或目录linux rm, mkdirlinux pwd显示当前目录linux pwdlinux ps显示当前进程信息lin…