【C语言:动态内存管理】

这篇具有很好参考价值的文章主要介绍了【C语言:动态内存管理】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【C语言:动态内存管理】,C_language,c语言,开发语言

前言

文章的标题是动态内存管理,那什么是动态内存管理?为什么有动态内存管理呢?
回顾一下以前学的知识,我们已经掌握的开辟内存的方式有以下几种:

char ch = 'a';
int val = 10;
float f_val = 12.8f;
int arr[20] = { 0 };
//....

上述开辟内存的方式有几个弊端:

  1. 开辟空间的大小是固定的
  2. 数组在声明的时候,必须指定数组的长度,数组空间⼀旦确定了大小就不能调整了

但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,那数组在编译时就开辟空间的方式就不能满⾜了。
C语言引⼊了动态内存开辟,让程序员自己可以申请和释放空间,就比较灵活了。

1.malloc

【C语言:动态内存管理】,C_language,c语言,开发语言
这个函数的功能是:向内存申请一块连续的内存空间,然后返回一个指向该空间的起始地址的指针

  • 如果空间开辟成功,则返回一个指向该空间起始地址的指针。
  • 如果空间开辟失败,则返回一个NULL指针。因此,函数的返回值需要做检查
  • 开辟的空间不会被初始化
  • 返回值的类型是void*,所以该函数并不知道所开辟空间的类型,需要空间的使用者自己决定。
  • 当该函数的参数是0是,返回值是未定义的,取决于编译器。
  • 头文件stdlib.h

使用malloc函数申请40个字节的空间
【C语言:动态内存管理】,C_language,c语言,开发语言
当函数的参数是0时,vs2019中是随机值
【C语言:动态内存管理】,C_language,c语言,开发语言
既然空间是程序员申请的,那么最后由谁释放呢?

  1. 程序员自己释放。
  2. 程序结束,操作系统回收

下面就来介绍如何释放

2.free

C语言提供了另外⼀个函数free,专⻔是⽤来做动态内存的释放和回收的,函数原型如下:
【C语言:动态内存管理】,C_language,c语言,开发语言

  • 该函数用来释放由malloc、calloc、realloc申请的空间的
  • 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
  • 如果参数 ptr 是NULL指针,则函数什么事都不做。
  • 该函数不会改变指针ptr的值,因此为了避免野指针的出现,要将其及时置为NULL。

【C语言:动态内存管理】,C_language,c语言,开发语言

3.calloc

【C语言:动态内存管理】,C_language,c语言,开发语言
该函数的功能跟malloc差不多,区别在于:

  • 该函数的参数有两个,一个是有几个元素,一个是每个元素的大小。
  • 该函数会将申请的空间初始化为全0。

【C语言:动态内存管理】,C_language,c语言,开发语言

4.realloc

【C语言:动态内存管理】,C_language,c语言,开发语言

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

  • ptr 是要调整的内存地址
  • size 调整之后新大小
  • 返回值为调整之后的内存起始位置。
  • 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间
  • realloc在调整内存空间的是存在两种情况:
    • 情况1:原有空间之后有足够大的空间
    • 情况2:原有空间之后没有足够大的空间
  • 情况1
    当是情况1 的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化
  • 情况2
    当是情况2的时候,原有空间之后没有⾜够多的空间时,扩展的⽅法是:在堆空间上另找⼀个合适⼤⼩连续空间来使⽤。这样函数返回的是⼀个新的内存地址。

既然该函数有两种特殊情况,那我们在使用时也应该更加注意:
下面的代码有没有问题呢?

int main()
{
	//1. 先申请一部分空间
	int* p = (int*)malloc(20);
	if (NULL == p)
	{
		perror("malloc");
		return 1;
	}
	//2.扩容空间
	p = (int*)realloc(p, 40);
	if (NULL == p)
	{
		perror("realloc");
		return 1;
	}
	//3.使用
	//.......
	
	free(p);
	p = NULL;
	return 0;
}

假如realloc开辟空间失败了,那么它会返回一个空指针,p就是空指针了。
好家伙,没给我扩容成功,我以前的数据也没了,真可以!
所以在接收realloc的返回值时,我们应该使用你一个临时变量接收,判断临时变量是不是空指针,然后再对p进行操作。
所以,应该这样写:

#include<stdlib.h>

int main()
{
	//1. 先申请一部分空间
	int* p = (int*)malloc(20);
	if (NULL == p)
	{
		perror("malloc");
		return 1;
	}
	//2.扩容空间
	int* tmp = NULL;
	tmp = (int*)realloc(p, 40);
	//先判断realloc的返回值
	if (tmp != NULL)
	{
		p = tmp;
		tmp = NULL;
	}
	//3.使用
	//....
	free(p);
	p = NULL;
	return 0;
}

5.动态内存常见错误

  1. 对NULL指针的解引用操作
  2. 对动态开辟空间的越界访问
  3. 对非动态开辟内存使用free释放

【C语言:动态内存管理】,C_language,c语言,开发语言

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

【C语言:动态内存管理】,C_language,c语言,开发语言

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

【C语言:动态内存管理】,C_language,c语言,开发语言

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

6.动态内存经典笔试题分析

  1. 题目一
void GetMemory(char* p)
{
	p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
}

此处是值传递,并不会为str真正开辟空间,str还是NULL。
【C语言:动态内存管理】,C_language,c语言,开发语言

  1. 题目二
char* GetMemory(void)
{
	char p[] = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}

p变量生命周期为GetMemory函数内,函数结束,变量销毁。使用一个已经被销毁的变量的地址,结果是不可预测的
【C语言:动态内存管理】,C_language,c语言,开发语言

3.题目三

void Test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}

str指向的空间被释放,那么str就是野指针了,但是str还是指向那块内存空间;向str中拷贝world,那就是非法访问了

7.柔性数组

  1. 什么是柔性数组

也许你从来没有听说过柔性数组(flexible array)这个概念,但是它确实是存在的。C99 中,结构中最后⼀个元素允许是未知大小的数组,这就叫做『柔性数组』成员。

struct s
{
	int i;
	char ch;
	int a[];  //int a[0]
};

其中a就是一个柔性数组。

  1. 柔性数组的特点
  • 结构中的柔性数组成员前⾯ 必须⾄少⼀个其他成员。
  • sizeof 返回的这种结构大小不包括柔性数组的内存
  • 包含柔性数组成员的结构体用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构体的大小,以适应柔性数组的预期大小。
  1. 柔性数组的使用

【C语言:动态内存管理】,C_language,c语言,开发语言

如果我们不使用柔性数组,那么如何实现上述代码呢?
【C语言:动态内存管理】,C_language,c语言,开发语言

虽然不适用柔性数组也能达到目的,但使用柔性数组有两个好处:

  1. 方便内存的释放

如果我们的代码是在⼀个给别⼈⽤的函数中,你在⾥⾯做了⼆次内存分配,并把整个结构体返回给⽤⼾。⽤⼾调⽤free可以释放结构体,但是⽤⼾并不知道这个结构体内的成员也需要free,所以你不能指望⽤⼾来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存⼀次性分配好了,并返回给⽤⼾⼀个结构体指针,⽤⼾做⼀次free就可以把所有的内存也给释放掉。

  1. 有利于访问速度

连续的内存有益于提⾼访问速度,也有益于减少内存碎⽚。

8.C/C++中的内存区域划分

【C语言:动态内存管理】,C_language,c语言,开发语言

  1. 栈区

栈区(stack):在执⾏函数时,函数内局部变量的存储单元都可以在栈上创建,函数执⾏结束时这些存储单元⾃动被释放。栈内存分配运算内置于处理器的指令集中,效率很⾼,但是分配的内存容量有限。栈区主要存放运⾏函数⽽分配的局部变量、函数参数、返回数据、返回地址等

  1. 堆区

堆区(heap):⼀般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。分配⽅方式似于链表。

  1. 静态区

数据段(静态区):存放全局变量、static修饰的变量。程序结束后由系统释放。

  1. 代码段

代码段:存放函数体(类成员函数和全局函数)的⼆进制代码

本次的分享就到这里啦!如有错误请纠正。文章来源地址https://www.toymoban.com/news/detail-774355.html

到了这里,关于【C语言:动态内存管理】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 动态内存管理(C语言)

    动态内存管理(C语言)

    我们已经掌握的内存开辟方式有 int val = 20;//在栈空间上开辟四个字节 char arr[10] = {0};//在栈空间上开辟10个字节的连续空间 但上述开辟内存的方式有两个特点 空间开辟大小是固定的 数组在声明时必须指定数组的长度,他所需要的内存在编译时分配 但是对于空间的需求,不仅

    2024年02月16日
    浏览(10)
  • 动态内存管理 --- C语言

    动态内存管理 --- C语言

    目录 1.为什么存在动态内存管理 2.动态内存函数的介绍 2.1 malloc 与 free  2.2 calloc 2.3 realloc 3.常见的动态内存错误 4.几个经典笔试题 6.柔性数组 我们已经掌握的内存开辟方式有: 但是上述的开辟空间的方式有两个特点: 空间开辟的 大小是固定的 。 数组在声明的时候, 必须指

    2024年02月11日
    浏览(15)
  • 【C语言:动态内存管理】

    【C语言:动态内存管理】

    文章的标题是动态内存管理,那什么是动态内存管理?为什么有动态内存管理呢? 回顾一下以前学的知识,我们已经掌握的开辟内存的方式有以下几种: 上述开辟内存的方式有几个弊端: 开辟空间的大小是固定的 数组在声明的时候,必须指定数组的长度,数组空间⼀旦确定

    2024年02月03日
    浏览(8)
  • C语言->动态内存管理

    C语言->动态内存管理

    文章目录  ✅作者简介:大家好,我是橘橙黄又青,一个想要与大家共同进步的男人😉😉 🍎个人主页:橘橙黄又青_C语言,函数,指针-CSDN博客 目的:学习malloc,free,calloc,realloc函数的使用。 内存函数在#includestdio.h头文件里面。 我们已经掌握的内存开辟⽅式有: 但是上述的

    2024年02月04日
    浏览(5)
  • 【C语言】动态内存管理

    【C语言】动态内存管理

    大家好,我是苏貝,本篇博客带大家了解动态内存管理,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️ 我们已经掌握的内存开辟方式有: int val = 20; 在栈空间上开辟四个字节 char arr[10] = {0}; 在栈空间上开辟10个字节的连续空间 但是上述的开辟空间的方式有

    2024年01月16日
    浏览(10)
  • 动态内存管理-c语言

    动态内存管理-c语言

    目录 1.为什么要有动态内存分配 2.malloc函数和free函数 malloc 函数原型 栗子 free 函数原型 栗子 3.calloc和***realloc*** 3.1calloc函数 原型如下: 栗子 3.2***recalloc*** 第一种情况 第二种情况 第三种情况 recalloc模拟实现calloc函数 4.六大常⻅的动态内存的错误 4.1对NULL指针的解引⽤操作

    2024年03月22日
    浏览(10)
  • C语言之动态内存管理

    C语言之动态内存管理

           在C语言中我们在栈上开辟的空间是固定的,一旦确定好大小就不能随意改变,就想你创建了 int i = 10; int arr[10] = {0}; int i 一旦确定下来就是四个字节,arr一旦确定好大小在重新运行时也是不能改变的。 为此C语言引入了动态内存空间开辟,这是给程序员自主开辟好空间

    2024年04月09日
    浏览(4)
  • 【C语言】动态内存的管理

    【C语言】动态内存的管理

    前言 本篇博客就来探讨一下动态内存,说到内存,我们以前开辟空间大小都是固定的,不能调整这个空间大小,于是就有动态内存,可以让我们自己选择开辟多少空间,更加方便,让我们一起来看看动态内存的有关知识吧 个人主页:小张同学zkf 若有问题 评论区见 感兴趣就

    2024年04月15日
    浏览(6)
  • 【进阶C语言】动态内存管理

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

    前言 📕作者简介: 热爱跑步的恒川 ,致力于 C/C++、Java、Python 等多编程语言,热爱跑步,喜爱音乐的一位博主。 📗本文收录于 C语言进阶 系列,本专栏主要内容为数据的存储、指针的进阶、字符串和内存函数的介绍、自定义类型结构、动态内存管理、文件操作等,持续更

    2023年04月18日
    浏览(7)
  • c语言中动态内存管理

    c语言中动态内存管理

    说到内存,大家一定都知道。但是有一种函数可以实现动态内存管理,下面大家一起学习。 经过c语言的学习,相信大家都知道如何开辟一块内存。 上面代码开辟的空间,有两个特点: 空间开辟大小是固定的。 数组在申明的时候必须指定数组的长度,数组空间一旦确定大小

    2024年04月27日
    浏览(12)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包