摘要:C语言中比较重要的就是指针,它可以用来链表操作,谈到链表,很多时候为此分配内存采用动态分配而不是静态分配。
本文分享自华为云社区《【云驻共创】C语言中动态内存分配的本质》,作者: G-washington。
C语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发。尽管C语言提供了许多低级处理的功能,但仍然保持着跨平台的特性,因为C语言具有可移植性,可拓展性,可重用性等特性,促使C语言仍然在编程语言排行榜上占据一定有利地位。而C语言中比较重要的就是指针,它可以用来链表操作,谈到链表,很多时候为此分配内存采用动态分配而不是静态分配。
内存分配的概念
通常定义变量(或对象),编译器在编译时都可以根据该变量(或对象)的类型知道所需内存空间的大小,从而系统在适当的时候为他们分配确定的存储空间。这种内存分配称为静态存储分配;有些操作对象只在程序运行时才能确定,这样编译时就无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为动态存储分配。所有动态存储分配都在堆区中进行。
内存不是取之不尽用之不竭,4g、8g、16g是常见的电脑内存大小,打开任务管理器,能看到不同的应用占据的内存情况。如果一个应用程序占了大部分内存,估计别的应用就资源紧张了,那这个应用可能会被卸载,找个节省内存的。
内存管理是计算机接近物理本质的操作,那些程序语言之下的动作,最终都要调动内存来实现。系统的资源不是无限的,系统上运行的程序也不是只有这一个,忽略内存,就会设计出危险的、冗余的代码产品,或者没法更好的交互。
动态内存分配的特点
动态内存是相对静态内存而言的。所谓动态和静态就是指内存的分配方式。动态内存是指在堆上分配的内存,而静态内存是指在栈上分配的内存。动态内存分配的本质就是,什么时候需要一块内存的时候,再分配这块内存;当不再需要某一块内存的时候,就可以把这块内存释放掉。这种灵活的内存分配方式,正好适合链表这种数据结构。
传统数组的缺点
数组与动态内存分配相比有以下缺点:
- 数组的长度必须事先指定,而且只能是常量,不能是变量。
- 因为数组长度只能是常量,所以它的长度不能在函数运行的过程当中动态地扩充和缩小。
- 对于数组所占内存空间程序员无法手动编程释放,只能在函数运行结束后由系统自动释放,所以在一个函数中定义的数组只能在该函数运行期间被其他函数使用。
而“传统数组”的问题,实际上就是静态内存的问题。但是动态内存就不存在这个问题,因为动态内存是由程序员手动编程释的,所以想什么时候释放就什么时候释放。只要程序员不手动编程释放,就算函数运行结束,动态分配的内存空间也不会被释放,其他函数仍可继续使用它。除非是整个程序运行结束,这时系统为该程序分配的所有内存空间都会被释放。
动态内存的申请与释放
动态内存的申请与释放主要依靠两个函数malloc和free。malloc 是一个系统函数,它是 memory allocate 的缩写。其中memory是“内存”的意思,allocate是“分配”的意思。顾名思义 malloc 函数的功能就是“分配内存”,要调用它必须要包含头文件<stdlib.h>。
malloc()函数会向堆中申请一片连续的可用内存空间;若申请成功 ,,返回指向这片内存空间的指针 ,若失败 ,则会返回NULL, 所以我们在用malloc()函数开辟动态内存之后, 一定要判断函数返回值是否为NULL;返回值的类型为void*型, malloc()函数并不知道连续开辟的size个字节是存储什么类型数据的 ,所以需要我们自行决定 ,方法是在malloc()前加强制转 ,转化成我们所需类型 ,如: (int*)malloc(sizeof(int)*n).
下面使用 malloc 函数写一个程序,程序的功能是:调用被调函数,将主调函数中动态分配的内存中的数据放大 10 倍。
输出结果是:*p = 100
free是释放函数,在堆中申请的内存空间不会像在栈中存储的局部变量一样 ,函数调用完会自动释放内存 , 如果我们不手动释放, 直到程序运行结束才会释放, 这样就可能会造成内存泄漏, 即堆中这片内存中的数据已经不再使用, 但它一直占着这片空间, 所以当我们申请的动态内存不再使用时 ,一定要及时释放 .不过需要注意的是,释放并不是指清空内存空间,而是指将该内存空间标记为“可用”状态,使操作系统在分配内存时可以将它重新分配给其他变量使用。
那么,当指针变量被释放后,它所指向的内存空间中的数据会怎样呢?free 的标准行为只是表示这块内存可以被再分配,至于它里面的数据是否被清空并没有强制要求。不同的编译器处理的方式可能不一样。我们就看一下 VC++6.0 这个编译器是怎么处理的:
可见在 VC++6.0 中,当指针变量被释放后,虽然它仍然是指向那个内存空间的,但那个内存空间中的值将会被重新置一个非常小的负数。动态创建的内存如果不用了必须要释放。注意,一个动态内存只能释放一次。如果释放多次程序就会崩溃,因为已经释放了,不能再释放第二次。
综上所述,malloc 和 free 一定要成对存在,一一对应。有 malloc 就一定要有 free,有几个 malloc 就要有几个 free,与此同时,每释放一个指向动态内存的指针变量后要立刻把它指向 NULL。
注意事项
1)释放一块内存的一部分是不允许的。动态分配的内存必须整块一起释放。但是,realloc函数可以缩小一块动态分配的内存,有效地释放它尾部的部分内存。
2)不要访问已经被free函数释放了的内存。假定对一个指向动态分配的内存的指针进行了复制,而且这个指针的几份拷贝分散于程序各处。你无法保证当你使用其中一个指针时它所指向的内存是不是已被另一个指针释放。还要确保程序中所有使用这块内存的地方在这块内存释放之前停止对它的使用。
3)当动态分配的内存不再需要使用时,应该被释放,这样可以被重新分配使用。分配内存但在使用完毕后不释放将引起内存泄漏(memory leak)。
C语言中动态内存分配的本质是什么?的更多相关文章
-
C语言中的内存分配与释放
C语言中的内存分配与释放 对C语言一直都是抱着学习的态度,很多都不懂,今天突然被问道C语言的内存分配问题,说了一些自己知道的,但感觉回答的并不完善,所以才有这篇笔记,总结一下C语言中内存分配的主要内容 ...
-
数据结构基础(1)--数组C语言实现--动态内存分配
数据结构基础(1)--数组C语言实现--动态内存分配 基本思想:数组是最常用的数据结构,在内存中连续存储,可以静态初始化(int a[2]={1,2}),可以动态初始化 malloc(). 难点就是数 ...
-
rt-thread中动态内存分配之小内存管理模块方法的一点理解
@2019-01-18 [小记] rt-thread中动态内存分配之小内存管理模块方法的一点理解 > 内存初始化后的布局示意 lfree指向内存空闲区首地址 /** * @ingroup Sys ...
-
C语言中动态内存的分配(malloc,realloc)
动态内存分配:根据需要随时开辟,随时释放的内存分配方式.分配时机和释放时机完全由程序员决定,由于没有数据声明,这部分空间没有名字.无法像使用变量或数组那样通过变量名或数组名引用其中的数据,只能通过指针 ...
-
c语言中的内存分配malloc、alloca、calloc、malloc、free、realloc、sbr
C语言跟内存分配方式 (1) 从静态存储区域分配.内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.例如全局变量,static变量. (2) 在栈上创建.在执行函数时,函数内局部变 ...
-
重拾c语言之动态内存分配
动态内存分配 传统数组的缺点: 1数组长度必须事先制定,且仅仅能是长整数不能是变量 2传统形式定义的数组该数组的内存程序无法手动释放 3数组一旦定义,系统就会为该数组分配的存储空间就会一直存在直到该函 ...
-
C++语言之动态内存分配
在C语言中,我们熟悉的内存分配与释放的最常用的接口分别是malloc , free .在C++中: 存在着更加方便的动态存储分配: 1.new 和delete 机制,new 它能更可靠控制存储区的分配 ...
-
C/C++中动态内存分配
代码段:用来存放程序执行代码的一块内存区域.这部分内存大小在程序运行前已经知道,通常属于只读,其中包括只读的字符串常量,不可改变 BBS段:用来存放存放程序中未初始化的全局变量及静态变量,属于静态内存 ...
-
c/c++中动态内存分配处理字符串的细节问题
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <malloc.h&g ...
随机推荐
-
Linux tree命令
Linux tree命令用于以树状图列出目录的内容. 执行tree指令,它会列出指定目录下的所有文件,包括子目录里的文件. 语法 tree [-aACdDfFgilnNpqstux][-I <范 ...
-
用GruntJS合并、压缩CSS资源文件
合并.压缩CSS资源文件用到了grunt-contrib-concat.grunt-css插件,自己npm就可以了,下面直接呈上package.json.Gruntfile.js代码 package. ...
-
poj 1191 棋盘分割(dp + 记忆化搜索)
题目:http://poj.org/problem?id=1191 黑书116页的例题 将方差公式化简之后就是 每一块和的平方 相加/n , 减去平均值的平方. 可以看出来 方差只与 每一块的和的平方 ...
-
resolvconf: Error: /etc/resolv.conf isn&#39;t a symlink, not doing anything.
一.问题出现的原因 resolv.conf默认是个软链接,resolvconf默认会检查resolv.conf不是软链接就报错 默认的情况是这样的: #ls -l /etc/resolv.conflr ...
-
HTML中鼠标滚轮事件onmousewheel处理
滚轮事件是不同浏览器会有一点点区别,一个像Firefox使用DOMMouseScroll ,ff也可以使用addEventListener方法绑定DomMouseScroll事件,其他的浏览器滚轮事件 ...
-
TV Metro界面(仿泰捷视频TV版)源码解析
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52822499 前言:上一篇介绍了 ...
-
something for learning
[Unity Shaders]法线纹理(Normal Mapping)的实现细节 https://blog.csdn.net/candycat1992/article/details/41605257
-
16.Odoo产品分析 (二) – 商业板块(9) – 网站生成器(1)
查看Odoo产品分析系列--目录 安装"电子商务"模块时,该模块会自动安装,但网站生成器是电子商务的前提,因此,先分析该模块,在下面就是对电子商务模块的分析. 1. 编辑网站 安装 ...
-
Ehcache BlockingCache 源码分析
BlockingCache是对Ehcache进行的扩展,BlockingCache内置了读写锁,不需要用户显示调用. 要彻底分析BlockingCache的原理,需要首先来看一下它内部用到的一些类. ...
-
Js基础知识5-函数返回值、函数参数、函数属性、函数方法
函数返回值 所有函数都有返回值,没有return语句时,默认返回内容为undefined,和其他面向对象的编程语言一样,return语句不会阻止finally子句的执行. function testF ...