C语言—动态内存管理

news2024/11/27 0:22:27

专栏:C语言
个人主页:HaiFan.
专栏简介:本专栏主要更新一些C语言的基础知识,也会实现一些小游戏和通讯录,学时管理系统之类的,有兴趣的朋友可以关注一下。

动态内存管理

  • 前言
  • 一、为什么会存在动态内存分配
  • 二、动态内存函数的介绍
    • 1.malloc和free
    • 2.calloc
    • 3.realloc
  • 三、常见的动态内存错误
    • 1.对NULL指针解引用操作
    • 2.对动态开辟空间的越界访问
    • 3.对非动态开辟内存使用free释放
    • 4.使用free释放一块动态开辟内存的一部分
    • 5.对同一块动态内存多次释放
    • 6.动态开辟内存忘记释放(内存泄漏)
  • 四、程序的内存开辟


前言

在这里插入图片描述


一、为什么会存在动态内存分配

在此之前,我们已经熟练掌握了创建变量,在创建变量的时候,计算机会自动根据我们所创建变量的类型来开辟一定大小的空间。

#include <stdio.h>

int main()
{
	int a = 1;//在栈空间上开辟四个字节
	int arr[10];//在栈空间上开辟40个字节的连续空间
}

但是,在创建变量的时候所开辟的空间大小是固定的,而且,数组在创建的时候,必须指定数组的长度,为此分配一定的空间。但是,对于这样的空间,可能会存在不够用,或者用不完的情况,这就造成了空间的浪费。那这个时候,就有了动态内存开辟。

二、动态内存函数的介绍

1.malloc和free

malloc和free
C语言为我们提供了一个动态开辟空间的函数。

void* malloc (size_t size);

这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
如果开辟成功,则返回一个指向开辟好空间的指针。
如果开辟失败,则返回一个NULL指针,因此在使用malloc函数的时候,返回值一定要做检查。
返回值的类型是void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者要自己决定类型。
如果参数size=0,malloc的行为是标准未定定义的,取决于编译器。


有开辟空间就有释放空间。
C语言提供了一个函数free,专门用来释放动态内存所开辟的空间。

void free (void* ptr);

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

mallco和free函数都声明在stdlib.h头文件中

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

int main()
{
	int num = 10;
	int arr[10] = { 0 };

	int* ptr = NULL;
	ptr = (int*)malloc(num * sizeof(int));
	if (ptr == NULL)//每用一次开辟内存的函数都要进行判断,
	{
		perror("malloc");
		exit(-1);
	}
	else
	{
		int i = 0;
		for (int i = 0; i < num; i++)
		{
			*(ptr + i) = 0;
			printf("%d ", *(ptr + i));

		}
	}
	free(ptr);//释放空间
	ptr = NULL;//free只会把除ptr之外开辟的空间给销毁,
	//并不会把ptr所在的空间销毁,如果不把ptr置为空,
	//ptr就成为了野指针,所以要把ptr也置为空
	return 0;
}

在这里插入图片描述

2.calloc

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

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

函数功能是为num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0。
与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。

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

int main()
{
	int* ptr = (int*)calloc(10, sizeof(int));
	if (ptr == NULL)
	{
		perror("calloc");
		exit(-1);
	}
	free(ptr);
	ptr == NULL;
	return 0;
}

在这里插入图片描述
所以如何我们对申请的内存空间的内容要求初始化,那么可以很方便的使用calloc函数来完成任务。

3.realloc

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

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

  1. ptr 是要调整的内存地址
  2. size 调整之后新大小
  3. 返回值为调整之后的内存起始位置。
    这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到 新 的空间。

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

  1. 原有空间之后有足够大的空间
    要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。
  2. 原有空间之后没有足够大的空间
    扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新的内存地址。
#include <stdio.h>
#include <stdlib.h>

int main()
{
	//1.用malloc开辟100个字节的空间
	int* ptr = (int*)malloc(100);
	if (ptr == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	for (int i = 0; i < 10; i++)
	{
		*(ptr + i) = 1;//赋值
		printf("%d ", *(ptr + i));
	}
	puts("");

	//2.
	ptr = (int*)realloc(ptr, 200);//把ptr扩容,扩到200字节
	if (ptr == NULL)
	{
		perror("realloc");
		exit(-1);
	}
	for (int i = 10; i < 20; i++)
	{
		*(ptr + i) = 2;//
	}
	for (int i = 0; i < 20; i++)
	{
		printf("%d ", *(ptr + i));
	}
	puts("");
	free(ptr);
	ptr = NULL;
	return 0;

}

在这里插入图片描述

三、常见的动态内存错误

1.对NULL指针解引用操作

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* ptr = NULL;
	*ptr = 20;
	
	return 0;
}

本来就是空指针,你在解引用算什么回事。
在这里插入图片描述
程序必崩。

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

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

int main()
{
	int* ptr = (int*)malloc(4);
	if (ptr == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	for (int i = 0; i <= 1; i++)//越界
	{
		*(ptr + i) = i;
	}
	free(ptr);
	ptr == NULL;
	return 0;
}

在这里插入图片描述

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

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

在这里插入图片描述

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

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

int main()
{
	int* ptr = (int*)malloc(4);
	if (ptr == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	ptr++;
	free(ptr);
	ptr == NULL;
	return 0;
	
}

在这里插入图片描述
开了多少空间就要释放多少空间。

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

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

int main()
{
	int* ptr = (int*)malloc(4);
	if (ptr == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	free(ptr);
	free(ptr);
	ptr == NULL;
	return 0;
	
}

在这里插入图片描述
释放一次就够了。

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

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

int main()
{
	int* ptr = (int*)malloc(4);
	if (ptr == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	return 0;
}

开辟了,就一定要还回去。

四、程序的内存开辟

C/C++程序内存分配的几个区域:

  1. 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结
    束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是
    分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返
    回地址等。
  2. 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分
    配方式类似于链表。
  3. 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
  4. 代码段:存放函数体(类成员函数和全局函数)的二进制代码。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/167064.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

磨金石教育分享||CG特效技术主要应用在哪几个领域

前面我们介绍了很多关于CG特效的知识&#xff0c;我们知道CG特效发展的历史以及重大意义。那么我们今天再来详细讨论一下CG特效主要应用的几个领域。近几年文化艺术的发展伴随着互联网信息技术高速传播。文化艺术产业变得多元&#xff0c;动漫、3A大作游戏、商业大片、虚拟现实…

Java 元注解

​ 元注解是负责对其它注解进行说明的注解&#xff0c;自定义注解时可以使用元注解。Java 5 定义了 4 个注解&#xff0c;分别是 Documented、Target、Retention 和 Inherited。Java 8 又增加了 Repeatable 和 Native 两个注解。这些注解都可以在 java.lang.annotation 包中找到…

前端压缩图片为指定宽高

压缩图片原理 通过原生的input标签拿到要上传的图片文件将图片文件转化成img元素标签在canvas上压缩绘制该HTMLImageElement将图片转化为一个包含图片展示的data URI&#xff0c;即图片被转换成base64编码的字符串 实现 通过原生的input标签拿到上传的图片文件 css部分<…

Linux 通过监控监控系统内存并定时重启指定服务

一、使用Free命令监控系统内存 1.1 查看系统内存情况 free -m1.1.1 获取空闲物理内存 echo Mem-free: `free -m | grep Mem | awk {print $4}`M1.1.2 获取缓冲区内存

php 安装curl扩展支持sftp协议

原因&#xff1a;php默认安装的依赖的libcurl.so中不支持sftp 协议 解决方法&#xff1a;先安装libssh2&#xff0c;curl安装时编译参数带–with-libssh2&#xff0c;这样可以支持sftp 一.编译安装libssh2-1.8.0 1.下载源码 地址: https://github.com/libssh2/libssh2 2.编译…

requests页面常用操作(post、put、get、head、patch、delete方法)

1 requests主要方法2 请求返回信息3 应用3.1 登录页面3.2 退出登录3.3 修改参数3.4 上传文件Requests 是一个 Python 的 HTTP 客户端库。每次调用 requests 请求之后&#xff0c;会返回一个 response 对象&#xff0c;该对象包含了具体的响应信息。可以通过requests模拟提交请求…

蓝桥杯 stm32 实现 ADC 采集数据功能 CubeMX

文章内的代码使用 HAL 库。 ADC 即 模数转换器&#xff0c;是指 将 连续变化的模拟信号 转换成 离散的数字信号 的器件。 文章目录前言一、ADC 原理图二、CubeMX 配置三、ADC 代码讲解总结前言 一、ADC 原理图 从原理图我们可以看到 STM32G431 内部集成 两个 最高位 12 位 的 A…

通信电子、嵌入式类面试题刷题计划03

文章目录021——"Hello, world!"022——计算圆的面积023——打印10x10的星号024——字符串打印025——打印26个英文字母026——strlen函数的用法027——sizeof函数的使用028——if else、变量赋值语句029——if else语句030——if elseif else语句&#xff0c;判断是…

数字IC设计、验证、FPGA笔试必会 - Verilog经典习题 ( 七)求两个数的差值

数字IC设计、验证、FPGA笔试必会 - Verilog经典习题 &#xff08;七&#xff09;求两个数的差值 &#x1f508;声明&#xff1a; &#x1f603;博主主页&#xff1a;王_嘻嘻的CSDN博客 &#x1f9e8;未经作者允许&#xff0c;禁止转载 &#x1f511;系列专栏&#xff1a;牛客Ve…

Redis作为缓存应用场景分析

为什么使用缓存 Redis是一个内存型数据库&#xff0c;也就是说&#xff0c;所有的数据都会存在与内存中&#xff0c;基于Redis的高性能特性&#xff0c;我们将Redis用在缓存场景非常广泛。使用起来方便&#xff0c;响应也是远超关系型数据库。 应用场景 Redis的应用场景非常…

绝了,超越YOLOv7、v8,YOLOv6 v3.0正式发布

超越YOLOv7、v8! YOLOv6 v3.0正式发布!!! YOLOv6 全新版本v3.0正式发布&#xff01;引入新的网络架构和训练方案&#xff0c;其中YOLOv6-S以484 FPS的速度达到45.0% AP&#xff0c;超过YOLOv5-S、YOLOv8-S&#xff0c;其代码刚刚开源 由于前段时间Ultralytics公司透露出V8的发…

马哥架构第2周课程作业

haproxy、nginx、lvs负责均衡相关的话题一. nginx和haproxy的异同点二. 实现haproxy四层地址透传&#xff0c;并且做基于cookie的会话保持2.1 haproxy四层地址透传2.2 基于cookie的会话保持2.2.1 配置选项2.2.2 配置示例2.2.3 验证 Cookie 信息三. 实现自定义错误页面和https的…

【学习笔记】【Pytorch】12.损失函数与反向传播

【学习笔记】【Pytorch】12.损失函数与反向传播一、损失函数的介绍1.L1Loss类的使用代码实现2.MSELoss类的使用3.损失函数在模型中的实现二、反向传播一、损失函数的介绍 参考&#xff1a; 损失函数&#xff08;loss function&#xff09; pytorch loss-functions 文档 作用&…

【JavaEE】基于TCP的客户端服务器程序

✨哈喽&#xff0c;进来的小伙伴们&#xff0c;你们好耶&#xff01;✨ &#x1f6f0;️&#x1f6f0;️系列专栏:【JavaEE】 ✈️✈️本篇内容:基于TCP的客户端服务器程序。 &#x1f680;&#x1f680;代码存放仓库gitee&#xff1a;JavaEE初阶代码存放&#xff01; ⛵⛵作者…

【JavaEE初阶】第二节.进程篇

文章目录 前言 一、操作系统 二、进程 2.1 进程的概念 2.2 进程的管理​​​​​​​​​​​​​​ 2.3 PCB 2.3.1 PCB里面的一些属性 2.3.2 进程的调度 2.3.3 进程的虚拟地址空间 2.3.4 进程间通信 总结 前言 本节内容我们继续对JavaEE的有关内容进行学习&#xff0c;…

汽车智能化,集度做加法

CES2023刚刚落下帷幕&#xff0c;这场名为“国际消费电子展”的业界盛会&#xff0c;近几年重心正明显转向智能汽车及其周边产业链。在2022年的CES上&#xff0c;集度与英伟达宣布合作&#xff0c;也透露了智能汽车研发的相关计划。而在本届CES之前、2022年末的广州车展上&…

一个关于image访问图片跨域的问题

一、背景 项目中遇到一个问题&#xff0c;同一个图片在 dom 节点中使用了 img 标签来加载&#xff0c;同时由于项目使用了 ThreeJS 3D 渲染引擎&#xff0c;在加载纹理时使用了 TextureLoader 来加载了同一张图片&#xff0c;而由于图片是在阿里云服务器上的&#xff0c;所以最…

SourceTree 拉取、重置提交、回滚、变基与合并

SourceTree的重置当前分支到此次提交 使用场景&#xff1a;“我想把已提交未推送的修改撤销” 使用模式说明软合并软合并是指将此次提交回滚到指定提交位置&#xff0c;但这个过程中会将修改过的文件暂存到暂存区。混合合并混合合并是指将此次提交回滚到指定的位置&#xff0c…

本来挺喜欢刷《剑指offer》的.......(第十一天)

跟着博主一起刷题 这里使用的是题库&#xff1a; https://leetcode.cn/problem-list/xb9nqhhg/?page1 目录剑指 Offer 66. 构建乘积数组剑指 Offer 68 - I. 二叉搜索树的最近公共祖先剑指 Offer 68 - II. 二叉树的最近公共祖先剑指 Offer 66. 构建乘积数组 剑指 Offer 66. 构建…

使用react-bmapgl绘制区域并判断是否重叠

需求如下&#xff1a; 在react项目中使用百度地图实现区域&#xff08;电子围栏&#xff09;的绘制绘制的区域类型为&#xff1a;1、多边形 2、圆形可绘制多个区域区域不能有重叠可重新编辑区域 代码如下: index.tsx import { useCallback, useEffect, useState } from rea…