传值、传址、空间释放详细图解

目录

前言

一.进程

1.1 进程的映射

1.2 进程的虚拟空间

二.函数传参

2.1 函数传参

2.2 函数传值

2.2.1 函数传值案例1

2.2.2 函数传值案例2

2.2.3 返回值为常量

2.3 函数传送地址

2.3  字符串使用


前言

详细介绍函数传值和传地址区别:进行数据操作的区别,函数传值为临时拷贝,不会对实参影响。而传地址时,就是传实参,是可以影响到实参的..........

一.进程

1.1 进程的映射

物理空间映射到虚拟空间是计算机内存管理中的一个重要概念,它允许程序使用的地址(虚拟地址)与计算机物理内存的地址(物理地址)之间进行转换

这种映射机制主要涉及以下几个关键点:

  1. 虚拟地址与物理地址:用户在编程时使用的地址称为虚拟地址或逻辑地址,而计算机物理内存中的地址称为物理地址。虚拟地址通过内存管理单元(MMU)的转换,映射到物理内存的实际位置。
  2. 虚拟存储空间与物理存储空间:虚拟地址对应的存储空间称为虚拟存储空间或逻辑地址空间,而物理地址对应的存储空间称为物理存储空间或主存空间。
  3. 虚拟页与物理页:在虚拟内存系统中,虚拟页是虚拟地址空间的一部分,它们会映射到物理内存中的物理页。这种分页机制使得程序可以拥有比实际物理内存更大的地址空间。
  4. 固定映射区与动态映射区:在固定映射区中,虚拟内存地址固定映射到物理内存的高端地址上,而在动态映射区和永久映射区中,虚拟地址不是固定的,可以被动态改变以映射到不同的物理地址上。
  5. 内存映射mmap:内存映射是一种将文件或其他资源映射到进程的虚拟地址空间的技术,这样进程就可以像访问内存一样访问这些资源。这通常用于优化文件I/O操作,因为它减少了数据从磁盘到内存的复制次数。

1.2 进程的虚拟空间

进程的虚拟空间是一个逻辑意义上的内存空间概念,它允许每个进程拥有独立的地址空间,使得程序的运行更加安全和高效

二.函数传参

2.1 函数传参

函数传参时可以通过传递地址的方式来实现对实际参数的修改。具体来说:

  1. 指针传递:在函数定义中,参数使用指针类型,调用函数时传递变量的地址。在函数内部,通过解引用操作可以访问和修改该地址指向的数据。这样,当函数返回时,原变量的值可能会被改变。
  2. 数组传参:在C语言中,当数组作为函数参数时,实际上传递的是数组首元素的地址。这是因为数组在内存中是连续存储的,所以传递首元素地址足以让函数访问整个数组。
  3. 引用传递:在某些编程语言(如C++)中,可以使用引用传递的方式。引用本质上是一个别名,它允许函数直接操作传递给它的变量。在函数内部对引用参数的任何修改都会反映到原始变量上。
  4. const修饰符:如果形参是指针并且加了const修饰,则该指针指向的数据是不可修改的。这有助于保护数据不被意外修改。
  5. 值传递:与地址传递相对的是值传递,值传递会创建一个实参的副本,函数内部的操作不会影响原始变量。但对于数组,由于发生了“降维”,实际上传入的是数组首元素的地址,因此即使是值传递,函数内部对数组元素的修改也是真实存在的。

总之,在实际应用中,选择哪种传递方式取决于具体的编程需求。例如,如果需要在函数内部修改外部变量的值,通常会选择指针传递或引用传递。而如果只是需要读取数据而不做修改,可能会选择值传递。

2.2 函数传值

2.2.1 函数传值案例1

这是最常见的传参方式,当调用函数时,实参的值被复制给形参,形参和实参分别占用不同的存储空间。在函数内部对形参的修改不会影响到外部的实参。这种方式简单且安全,但可能会因为参数复制而降低效率。

 #include<stdio.h>#include <stdlib.h>#include <string.h>void GetMemory1(char *p) // p ==== NULL{*p = (char *)malloc(100); // 向系统申请100个字节的堆空间, 让p 指向该区域}void Test1(void){char *str = NULL;GetMemory1(str); /// str ==== NULL// 经过GetMemory1 的操作后 str的指向依然没有变换还是指向NULLstrcpy(str, "hello world"); // 提示: 拷贝字符串, 把"hello world" 拷贝到str 所指向的内存空间中// 拷贝函数出现段错误printf("%s\n" , str);}int main(int argc, char const *argv[]){Test1();return 0;}

函数传值进行操作内存时,需要注意,如下:调用开辟内存函数时,没有传入地址,会出现野指针问题。这样传值就是错误的,正确的写法写在后面传地址案例中。

2.2.2 函数传值案例2

这里参考使用static数据段的操作

#include<stdio.h>#include <stdlib.h>#include <string.h>
char *GetMemory2(void)
{// 数组 p 所存放的位置为 栈空间, 当函数 GetMemory2 退出返回时, 该区域会被系统回收// 不应该返回该内存中的地址// 可以使用 static 来修饰该数组, 使其的内存区域改为数据段static char p[] = "hello world";return p;
}void Test2(void){char *str = NULL;str = GetMemory2();printf("TEST‐2:%s\n",str);}
int main(int argc, char const *argv[])
{Test2();return 0;
}

这里如果不使用static,程序会报错,因为它是传送值的

2.2.3 返回值为常量

这里的函数调用的返回值为常量,也就是存储在虚拟空间数据段

 #include<stdio.h>
#include <stdlib.h>
#include <string.h>
// TEST3
char *GetMemory3(void)
{// 直接返回 常量区的内存地址 , 注意该区域只读return "hello world";
}
void Test3(void)
{char *str = NULL;str = GetMemory3();printf("TEST‐3:%s\n",str);}int main(int argc, char const *argv[])
{Test3();return 0;
}

2.3 函数传送地址

在这种传参方式中,实参的地址被传递给形参,形参通常是指针类型。函数内部通过指针来访问和修改实参的值。这种方式允许函数修改外部变量的内容,适用于需要输出结果或者大型数据结构的情况。

 #include<stdio.h>#include <stdlib.h>#include <string.h>void GetMemory1(char **p) // p ==== NULL{*p = (char *)malloc(100); // 向系统申请100个字节的堆空间, 让p 指向该区域}void Test1(void){char *str = NULL;GetMemory1(&str); /// str ==== NULLstrcpy(str, "hello world"); // 提示: 拷贝字符串, 把"hello world" 拷贝到str 所指向的内存空间中printf("%s\n" , str);}int main(int argc, char const *argv[]){Test1();return 0;}

这里的传值为传地址,把char* str 的地址&str 传入GetMemonry1(char **p)作为形参,

解引用后*p 其实就是str 。调用的函数进入栈中进行内存的开辟操作,又因为str==*p,所以

即使栈销毁后str仍然指向malloc开辟的空间。

2.3  字符串使用

调用函数时,strcopy字符串时,存在'\0',

#include<stdio.h>
#include <stdlib.h>
#include <string.h>// TEST6void Test6(){char *str=(char *)malloc(100);strcpy(str, "hello");printf("TES1:%s\n" ,str); // 输出 hellostr+=6; //strcpy(str, "world");printf("TES2:%s\n" ,str); //输出 wordstr-=6;printf("TES3:%s\n" ,str); //输出 hello*(str+5)=' ';printf("TES4:%s\n" ,str); //输出 hello word}
int main(int argc, char const *argv[])
{Test6();return 0;
}

以上是本期补齐内容,若有不懂或者错误,欢迎评论与私信!!!

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

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

相关文章

c++算法学习笔记 (11) 离散化

1.前置知识&#xff1a; unique是 c标准模板库STL中十分实用的函数之一&#xff0c;使用此函数需要#include <algorithm>头文件 该函数的作用是“去除”容器或者数组中相邻元素的重复出现的元素。 (1) 这里的去除并非真正意义的erase&#xff0c;而是将重复的元素放到容…

VMware workstation pro 16 虚拟机的安装

VMware workstation pro 16 虚拟机的安装 VMware 16下载VMware 16安装VMware 16许可 VMware 16下载 下载地址&#xff1a; VMware workstation pro 16 官网下载地址 VMware 16安装 安装向导&#xff0c;点击下一步勾选我同意许可协议中的条款&#xff0c;点击下一步 更改安…

被奔驰看上的“人”

上周五&#xff0c;人形机器人公司、NASA 合作伙伴 Apptronik 宣布已与梅赛德斯奔驰&#xff08;以下简称奔驰&#xff09;达成一项商业协议&#xff0c;试点将身高 1.7 米、体重 140 多斤的双足机器人 Apollo 用于制造业。奔驰也成为继宝马、蔚来汽车之后最新尝试人形机器人的…

nodejs实现链接shp的属性信息(替换字段或者追加字段)

写在前面 偶尔听到同事说一个数据处理重复性的流程太多&#xff0c;就了解了下&#xff0c;原来是1份shp数据对应着一个xls属性文件&#xff0c;需要把xls文件里的一部分属性更新到shp的相关字段中&#xff0c;当然这种操作是可以用ArcGIS或者QGIS实现&#xff0c;但是当数据特…

综合交易模型----可转债三低策略实盘qmt版,提供源代码

链接 综合交易模型----可转债三低策略实盘qmt版&#xff0c;提供源代码 (qq.com) 可转债3低策略是指选择正股市值低、转债余额低、溢价率低的可转债进行投资的策略。 市值低&#xff1a;指的是可转债对应的正股市场价值较小&#xff0c;这通常意味着需要较少的资金就可以对股价…

jeecg启动Sentinel 一直是空白页面 解决办法用 外部 Sentinel SpringCloud之Sentinel概述和安装及简单整合

jeecg启动Sentinel 一直是空白页面 解决办法用 外部 Sentinel SpringCloud之Sentinel概述和安装及简单整合 文章目录 jeecg启动Sentinel 一直是空白页面 解决办法用 外部 Sentinel SpringCloud之Sentinel概述和安装及简单整合 Sentinel概述基本介绍 Sentinel安装下载地址: http…

聊聊AI时代学习这件事本身应该发生什么样的变化

随着 AI 大模型 的爆发&#xff0c;我们身处这个时代&#xff0c;应该怎么样去学习去了解这些前言的技术&#xff1f;可能很多人会说我英文不好&#xff0c;我算法不行&#xff0c;无法深入去了解 AI 大模型相关的知识吧&#xff1f; 没关系&#xff0c;其实博主也跟大家一样&…

注册登录Vue3+ElementPlus代码

1、app.vue <script setup>import LoginVue from /views/Login.vue </script><template><LoginVue/> </template> 2、Login.vue <script setup> import { User, Lock } from "element-plus/icons-vue"; import { ElMessage } …

[小程序开发] 外部样式类

一、外部样式类 在使用组件时&#xff0c;组件使用者可以给组件传入CSS类名&#xff0c;通过传入的类名修改组件的样式。 如果需要使用外部样式类修改组件的样式&#xff0c;在Component中需要用extemalClasses定义若干个外部样式类。 二、使用步骤 1、在Component中用externa…

C++面试100问!(一)

STL中MAP数据存放形式&#xff1f; 红黑树。unordered map底层结构是哈希表。 STL有什么基本组成&#xff1f; 容器、迭代器、仿函数、算法、分配器、配接器&#xff0c; 他们之间的关系&#xff1a;分配器给容器分配存储空间&#xff0c;算法通过迭代器获取容器中的内容&…

实在智能Agent——RPA终极进化方向

RPA技术备受瞩目&#xff0c;它通过“机器人”自动化了人力执行的重复性、低复杂度任务&#xff0c;解放了员工并降低了企业成本。RPA机器人全天候运行&#xff0c;避免人为错误&#xff0c;高效处理任务&#xff0c;成为处理事务、操作数据、回应查询的理想选择。在管理后台&a…

第四百一十回

文章目录 1. 概念介绍2. 方法与细节2.1 获取方法2.2 使用细节 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何获取当前系统语言"相关的内容&#xff0c;本章回中将介绍如何获取时间戳.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章…

实体店运营方案大全:从选址到日常管理的全面指导

想开实体店或正在创业的朋友们&#xff0c;大家好&#xff01;今天&#xff0c;我作为一个鲜奶吧5年的创业者&#xff0c;为大家分享一份实体店运营方案大全&#xff0c;涵盖从选址到日常管理的各个方面。我在实体店方面有一些心得体会&#xff0c;今天就来和大家聊聊&#xff…

【面试自测】Java并发

Synchronized 用 过 吗 &#xff0c; 其 原 理 是 什 么 &#xff1f;获 取 对 象 的 锁 &#xff0c; 这 个 “ 锁 ” 到 底 是 什 么 &#xff1f; 如 何 确 定 对 象 的 锁 &#xff1f;什 么 是 可 重 入 性 &#xff0c; 为 什 么 说 Synchronized 是 可 重 入 锁 &#x…

【软考】系统集成项目管理工程师(十九)收尾管理【1分】

一、项目收尾的内容 二、总结 三、软件后续工作 练一练 【例1-17上】&#xff08;B&#xff09;不属于项目验收的内容。 A.验收测试 B.系统维护工作 C.项目终验 D.系统试运行 【例2-17上】信息系统集成项目完成验收后要进行一个综合性的项目后评估,评估的内容一般包括&#…

uView LoadingIcon 加载动画

此组件为一个小动画&#xff0c;目前用在uView的loadMore加载更多等组件的正在加载状态场景。 #平台差异说明 App&#xff08;vue&#xff09;App&#xff08;nvue&#xff09;H5小程序√√√√ #基本使用 通过mode设定动画的类型&#xff0c;circle为圆圈的形状&#xff0…

探索Spring中的属性注入:@Value注解解析与应用

探索Spring中的属性注入&#xff1a;Value注解解析与应用 探索Spring中的属性注入&#xff1a;Value注解解析与应用摘要引言正文作用代码准备示例注入字符串注入属性注入Bean及其属性 其他属性注入优先级问题对Value属性注入的扩展Spring Boot对Value类型转换的扩展 代码案例演…

【单调栈】[USACO09MAR] Look Up S

题目描述 约翰的 N N N 头奶牛站成一排,奶牛 i i i 的身高是 H i H_i Hi​。现在,每只奶牛都在向右看齐。对于奶牛 i i i,如果奶牛 j j j 满足 i < j i<j i<j 且 H i < H j H_i<H_j Hi​<Hj​,我们可以说奶牛 i i i 可以仰望奶牛 j j j。 求出…

第三门课:结构化机器学习项目-机器学习策略

文章目录 1 机器学习策略一1.1 为什么是ML策略&#xff1f;1.2 正交化1.3 单一数字评估指标1.4 满足和优化指标1.5 训练、开发及测试集划分1.6 开发集和测试集的大小1.7 什么时候改变开发、测试集和指标&#xff1f;1.8 为什么是人的表现&#xff1f;1.9 可避免偏差1.10 理解人…

C/C++面试题

1、static的作用 1)修饰局部变量 概念:当使用static关键字修饰局部变量时,该变量就变成了静态局部变量。这意味着它不再是传统的自动存储期变量,而是具有静态存储期。 作用域:静态局部变量的作用域确实没有变化,它仍然是在其定义的局部范围内,即它所在的代码块(例如函…