指针与数组--动态数组(1)[1、C程序的内存映像 2、动态内存分配]

news2025/1/13 15:55:34

目录

一、C程序的内存映像

二、动态内存分配

        1、malloc()函数

        2、calloc()函数

        3、free()函数

        4、realloc()函数


一、C程序的内存映像

        一个编译后的C程序 获得并使用4块在逻辑上不同且用于不同目的的内存储区,如下图所示。

        从内存的低端开始,第一块内存为只读存储区,存放程序的机器码和字符串字面量等制度数据。

        第二块为静态存储区 ,用于存放程序中的全局变量和静态变量等。

        第三部分和第四部分称为堆(heap)和栈(stack),为动态存储区。

其中,堆(heap)用于保存函数调用时的返回地址、函数的形参、局部变量即cpu的当前状态等程序的运行信息。堆是一个自由存储区,程序可利用C的动态内存分配函数来使用它。

        虽然这4块区域的实际物理布局随CPU的类型和编译程序的实现而异。

C语言程序中变量的内存分配方式有以下三种:

(1)从静态存储区分配

        程序的全局变量和静态变量都在静态存储区上分配,且在程序编译时就已经分配好了,在程序运行期间时钟占据这些内存,仅在程序终止前,才被操作系统收回。

(2)在栈上分配

        在执行函数调用时,系统在栈上为函数内的局部变量及形参分配内存,函数执行结束时,自动释放这些内存。栈内存分配运算内置于处理器的指令集中,效率很高,但是容量有限。如果往栈中压入的数据超出预先给栈分配的容量,那么就会出现栈溢出,从而使程序运行失败。

(3)从堆上分配

        在程序运行期间,用动态内存分配函数来申请的内存都是从堆上分配的。

        动态内存的生存期是由程序员自己来决定的,使用非常灵活,但也最易出现内存泄漏等问题。为防止内存泄漏的发生,程序员必须及时调用free()释放已不再使用的内存。

二、动态内存分配函数

在C语言中,指针之所以重要,原因有以下4点:

(1)指针为函数提供修改变量值的手段;

(2)指针为C的动态内存分配系统提供支持;

(3)指针为动态数据结构(如链表、队列、二叉树等)提供支持;

(4)指针可以改善某些子程序的效率。

        在前面文章中,我们已经了解到指针的一个重要应用是用指针作函数参数,为函数提供了一种修改变量的手段。当用指针作函数形参时,须将函数外的某个变量的地址传给函数形参列表中相应的指针变量,以便函数内的代码通过指针变量来改变函数外的这个变量的值。

        此外,因指针的增1和减1运算速度很快,所以用指针变量来寻址数组元素可提高程序的执行效率。

        指针的另一个重要应用是把指针与动态内存分配函数联用,它使得实现动态数组(Dynamically Allocated Array)称为可能。

        动态内存分配(Dynamic Memory Allocation)是指在程序运行时为变量分配内存的一种方法。

        全局变量是编译时分配的,非静态的局部变量使用栈空间,因此两者在程序运行时既不能添加,也不能减少。而实际应用中,有时在程序运行中需要数量可变的内存空间,即在运行时才能确定要用多少个字节的内存来存放数据。(c99可以支持动态数组定义方式,但是c89就不支持,必须使用宏常量。)定义方式如下:

int  m,n;

int  a[m][n];

        能否在程序运行的过程中根据用户的需求生成可变长度的动态数组呢?

        这就要用动态内存分配函数来实现。C的动态内存分配函数从堆上分配内存。使用这些函数时只要在开头将头文件<stdlib.h>包含到源程序中即可。

1、malloc()函数

        函数malloc()用于分配若干字节的内存空间,返回一个指向该内存首地址的指针。若系统不能提供足够的内存单元,函数将返回空指针NULL。

函数malloc()的原型为:

        void *malloc(unsigned int size); 

其中,size表示向系统申请空间的大小,函数调用成功将返回一个指向void类型的指针。

        void * 指针式ANSI  C新标准中增加的一种指针类型,具有一般性,通常称为通用指针(Generic Pointer)者无类性的指针(Typeless Pointer),常用来说明其基类型未知的指针,即声明了一个指针变量,但未指定它可以指向哪一种基类型的数据。因此,若将函数调用的返回值赋予某个指针,则应先根据该指针的基类型,用强转的方法将返回的指针值强转为所需要的类型,然后在进行赋值操作。

例如:  int  *pi  =  NULL;    pi = (int *)malloc(2);

其中,malloc(2)表示申请一个大小为2个字节的内存,将malloc(2)返回值的 void *类型强转为int * 类型后在赋值给int型指针变量pi,即用int型指针变量pi指向这段存储空间的首地址。            若不能确定某种类型所占内存的字节数,则须使用sizeof()计算系统中该类型所占内存的字节数,然后再用malloc()向系统申请相应字节数的存储空间。

例如:pi = (int *)malloc(sizeof(int));///这种方法有利于提高程序的可移植性。

2、calloc()函数

        函数calloc()用于给若干同一类型的数据项分配连续的存储空间并赋值为0,其函数原型为:        void * alloc(unsigned int num,unsigned int size);

它相当于一个声明了一个一维数组。其中,第一个参数num表示向系统申请的内存空间量,决定了一维数组的大小,第二个参数size表示申请的每个空间的字节数,确定了数组元素的类型。而函数的返回值就是数组的首地址。

        若函数调用成功,则返回一个指向void类型的连续存储空间的首地址,否则返回空指针NULL。若要将函数的返回地址赋值给某个指针变量,则应先根据该指针的基类型,将其强转为与指针类型相同的数据类型,然后在进行赋值操作。

例如:float *pf  =  NULL;pf  =  (float*)calloc(10,sizeof(float));

表示向系统申请了10个连续的float型存储单元,并用指针pf指向该连续内存的首地址,系统申请的总的内存字节数为10×sizeof(float),相当于使用下面的语句:

pf  =  (float*)malloc(10*sizeof(float));

但从安全角度考虑,使用calloc()更加明智,因为与malloc()相比,calloc()能将自动分配的内存初始化为0。

3、free()函数

        函数free()的功能是释放向系统动态申请的由指针p指向的存储空间,其原型为:

void   free (void *p);

该函数无返回值。唯一的形参p只能由malloc()和calloc()申请内存是返回的地址。

该函数执行后,将以前分配的由指针p指向的内存返回给系统,以便由系统重新支配。

4、realloc()函数

        函数realloc()用于改变原来分配的存储空间的大小,其原型为:

void *realloc(void *p,unsigned int szie); 

该函数的功能是将指针p所指向的存储空间的大小改为size个字节,函数返回值是新分配的存储空间的首地址,与原来分配的首地址不一定相同。

        由于动态内存分配的存储单元是无名的,只能通过指针变量来引用它们,所以一旦改变了指针的指向,原来分配的内存即数据也就随之丢失。因此不要轻易改变该指针的变量值。 

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

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

相关文章

vue+leaflet 使用js自定义封装动画marker样式点

效果图 1. 引入leaflet import L from leaflet2. 使用原生js实现 import L from leaflet; import ../assets/css/blinkmarker.css; L.blinkMarker (point, property) > {// 使用js标签,便于操作,这个temDivEle的作用是将divEle通过innerHTML的方式获取为字符串var temp…

Nacos 打通 CMDB 实现就近访问

博主介绍&#xff1a;✌全网粉丝4W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战、定制、远程&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面…

小程序 体验版 快速配置https服务接口 - 项目是nodeJS配置本地https服务,不用下载源码不用付费,直接使用Git的openssh功能(亲测有效)

背景 学习网易云音乐小程序开发&#xff0c;用了老师的node JS做后端服务器&#xff0c;上线小程序体验版必须要https接口。 接下来就是配置NodeJs服务https踩的坑跟发现的惊喜。 配置https 下载与配置 密钥生成 1 运行命令 &#xff1a; openssl genrsa -out privatekey.p…

BST有缺陷--红黑树(RBT)应运而生

1.首先介绍一下什么是BST&#xff08;二叉查找树&#xff09; 若其左子树非空&#xff0c;则左子树上所有节点的值都小于根节点的值若其右子树非空&#xff0c;则右子树上所有节点的值都大于根节点的值其左右子树都是一棵二叉查找树二叉排序树通过中序遍历可以得到递增序列 如下…

技能树-网络爬虫-selenium

文章目录 前言一、selenium二、selenium 测试用例总结 前言 大家好&#xff0c;我是空空star&#xff0c;本篇给大家分享一下《技能树-网络爬虫-selenium》。 一、selenium Selenium是web自动化测试工具集&#xff0c;爬虫可以利用其实现对页面动态资源的采集&#xff0c;对于…

一位老程序员的忠告:别想着靠技术生存一辈子

注&#xff1a;本文系转载。 笔者目前是自己单干&#xff0c;但此前有多年在从事软件开发工作&#xff0c;回头想想自己&#xff0c;特别想对那些初学JAVA/DOT、NET技术的朋友说点心里话&#xff0c;希望我们的体会多少能给你们一些启发。 一、 在一个地方工作8小时就是“穷”…

Python多线程与多进程教程:全面解析、代码案例与优化技巧

文章目录 引言多线程多线程概述案例1&#xff1a;使用多线程实现并发下载文件案例2&#xff1a;使用多线程处理CPU密集型任务 使用threading模块案例1&#xff1a;自定义线程类并启动线程案例2&#xff1a;使用锁保护共享资源 线程同步与互斥案例&#xff1a;使用锁实现线程安全…

css用法总结

1. 块级元素合并时边框重叠问题的解决方案 设置边框2px 红色 如果不做处理&#xff0c;仅仅添加边框则会是这个样子 设置处理后的样式 代码展示 2. 拥有边框的div , hover时的展示效果 代码展示 3. img 和 文字环绕展示 代码展示 设置左浮动即可 4. text-align: center; 可…

Linux——Samba文件共享服务

个人简介&#xff1a;云计算网络运维专业人员&#xff0c;了解运维知识&#xff0c;掌握TCP/IP协议&#xff0c;每天分享网络运维知识与技能。座右铭&#xff1a;海不辞水&#xff0c;故能成其大&#xff1b;山不辞石&#xff0c;故能成其高。 个人主页&#xff1a;小李会科技的…

Go语言基础-基础语法

前言&#xff1a; \textcolor{Green}{前言&#xff1a;} 前言&#xff1a; &#x1f49e;这个专栏就专门来记录一下寒假参加的第五期字节跳动训练营 &#x1f49e;从这个专栏里面可以迅速获得Go的知识 本文主要是根据今天所学&#xff08;链接放在了最后&#xff09;总结记录的…

please specify ‘programme‘ in launch.json

故障现象&#xff1a; 在windows下点击F5&#xff0c;以运行vscode代码&#xff0c;在屏幕右下角出现这个错误提醒&#xff1b; 故障原因&#xff1a; 在配置文件&#xff08;settings.json或者launch.json&#xff09;中&#xff0c;缺少“program”这个参数配置&#xff1b…

SpringBoot 如何使用 Actuator 进行应用程序监控

SpringBoot 如何使用 Actuator 进行应用程序监控 在现代的应用程序开发中&#xff0c;应用程序监控是非常重要的&#xff0c;因为它可以帮助我们快速发现和解决问题。Spring Boot Actuator 是 Spring Boot 提供的一个强大的监控和管理工具&#xff0c;它可以帮助我们监控和管理…

0003Java程序设计-SSM+JSP现代家庭教育网站

摘 要 本毕业设计的内容是设计并且实现一个基于java技术的现代家庭教育网站。它是在Windows下&#xff0c;以MYSQL为数据库开发平台&#xff0c;java技术和Tomcat网络信息服务作为应用服务器。现代家庭教育网站的功能已基本实现&#xff0c;主要包括主页、个人中心、会员管理、…

Maven如何创建Maven web项目

1、创建一个新的模块: 1.1 使用骨架点一下&#xff0c;这里 1.2 找到maven-archetype-webapp项目&#xff0c;选中点击&#xff0c;一路next就行。 1.3 删除不必要的maven配置&#xff1a;&#xff08;这里我不需要&#xff0c;针对自己情况而定&#xff09; 可以从name这里开…

figma设计软件专业版教育优惠学生使用edu邮箱免费教程

产品介绍 今天一个买家发了一个链接问是否可以用&#xff0c;本站也是第一次见到&#xff0c;就测试了下可以使用教育优惠后准备分享给大家。本站的大多数教育优惠线报其实都是很多网友买家提供的。 Figma是一款用于数字项目的基于云的设计和原型的设计工具软件。 这样做的目…

Python应用实例(一)外星人入侵(二)

1.添加飞船图像 下面将飞船加入游戏中。为了在屏幕上绘制玩家的飞船&#xff0c;我们将加载一幅图像&#xff0c;再使用Pygame方法blit()绘制它。 为游戏选择素材时&#xff0c;务必要注意许可。最安全、最不费钱的方式是使用Pixabay等网站提供的免费图形&#xff0c;无须授权…

强者游戏-敢来挑战否-Amazon DeepRacer League

Amazon DeepRacer中国峰会总决赛 Amazon DeepRacer 自动驾驶赛车名校邀请赛会在6月27日-28日举办的Amazon DeepRacer中国峰会总决赛时同步启动。勇哥的目标是拿个比较好的名词。大家如果有参加这次活动的可以过来一起搞哦。下面我来具体介绍一下这次峰会&#xff0c;以及比赛的…

PyTorch C++ 前端是 PyTorch 机器学习框架的纯 C++ 接口

使用 PyTorch C 前端 PyTorch C 前端是 PyTorch 机器学习框架的纯 C 接口。 虽然 PyTorch 的主要接口自然是 Python&#xff0c;但此 Python API 位于强大的 C 代码库之上&#xff0c;提供基本的数据结构和功能&#xff0c;例如张量和自动微分。 C 前端公开了纯 C 11 API&…

常见面试题之线程基础知识

1. 线程和进程的区别&#xff1f; 程序由指令和数据组成&#xff0c;但这些指令要运行&#xff0c;数据要读写&#xff0c;就必须将指令加载至CPU&#xff0c;数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理IO的。 当一…

DataStructure01|ArrayList和顺序表

ArrayList与顺序表 1.线性表 ​ 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列… ​ 线性表在逻辑上是线性结构&#xff0c;也就说…