从0到1入门C++编程——03 内存分区、引用、函数高级应用

news2025/4/7 15:29:13

文章目录

  • 一、内存分区
  • 二、引用
  • 三、函数的高级应用
    • 1.默认参数
    • 2.占位参数
    • 3.函数重载

一、内存分区

C++程序在执行时,会将内存大致分为4个区,分别是代码区、全局区、栈区和堆区。
代码区用来存放函数体和二进制代码,由操作系统进行管理。
全局区用来存放全局变量、静态变量、字符串常量以及全局常量(const修饰的变量)。
栈区是由编译器自动分配和释放,用来存放函数的参数值、局部变量等。
堆区由程序员分配和释放,如果程序员分配了内存但没释放,程序结束时由操作系统回收,但是这种情况下有可能造成内存泄露。
内存分区可以使数据存放在不同的区域,并赋予其不同的生命周期,可以使得编程更加灵活。
程序编译后生成了可执行程序,未执行程序之前分为两个区域,代码区和全局区。代码区存放CPU执行的机器指令,代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可;代码区是只读的,防止程序意外的被修改。全局区在程序结束后由操作系统释放。
由下图可以看到,全局变量的地址比局部变量的地址低。这是因为全局变量存放在全局区,局部变量存放在栈区。
在这里插入图片描述
注意局部常量和全局常量存放的位置是不一样的,局部常量仍然存放在栈区,而全局常量存放在全局区。
在栈区中需要注意,不要返回局部变量的地址! 因为局部变量存放在栈区,栈区的数据在函数执行完以后自动释放。
下面的例子可以看到,函数返回了局部变量的地址,在main函数中进行了接收,第一次解引用得到了正确的值是因为编译器做了保留,第二次打印数据就不再保留了,对返回的局部变量的地址操作是非法的。
在这里插入图片描述
对数组而言也是一样的,不能返回数组地址进行读写操作。
在这里插入图片描述
如果将局部变量变为静态变量,那么即使函数返回后,数据依然可以访问,因为变量的存放区域不再是栈区,而是全局区。
在这里插入图片描述
在C++中利用关键字new在堆区开辟内存,并以指针接收内存。 new什么类型的数据,就以什么类型的指针接收其地址,括号里面的值是给堆区开辟的内存初始化数值。程序员不释放,堆区中的数据一直存放到程序运行结束。
在这里插入图片描述
释放new开辟的内存使用关键字delete。
在堆区中开辟数组要用中括号,释放的时候要先在delete后加[]再加指针释放,释放单个数据的时候直接在delete后加指针即可。
在这里插入图片描述


二、引用

引用的作用是给变量起别名。引用必须初始化,且初始化以后不可以改变。
语法:数据类型 &别名 = 原名;
引用的本质在C++内部实现是一个指针常量,指针的指向不可修改,但是指针指向的值可以修改。

int a = 10;
int &b = a;  //相当于 int* const b = a;

C++ 推荐引用技术,语法方便,其涉及的指针操作都由编译器做了。
在给变量起别名的时候,数据类型要与原变量一致。
在这里插入图片描述
引用可以作为函数参数传递,其效果和指针一样,例如下面交换两个数的例子。
在这里插入图片描述
通过引用参数产生的效果同按地址传递时一样的,引用的语法更加清楚简单。
引用归根结底还是对地址的操作,下面是传递参数的三种不同方式。
指针方式是地址传递,因此在主函数和函数体中的变量地址是一样的。
在这里插入图片描述
引用也是地址传递,主函数和函数体中的变量地址一样。
在这里插入图片描述
值传递则与上面两种不一样,变量在主函数中的地址和函数体中的地址是不一样的,这也是为什么经过函数交换后实际的变量值没有发生交换,因为函数中操作的地址是在栈中另外开辟的。
在这里插入图片描述
引用可以作为函数的返回值,但是不要返回局部变量的引用!
返回局部变量的引用和返回局部变量的地址是一样的,函数返回后内存会被释放掉,再对该内存操作就是非法的,下面的打印第一次虽然是对的,但只是临时保存的。
在这里插入图片描述
函数的返回值是引用,函数调用可以作为左值!
函数调用作为左值相当于给返回的引用进行赋值操作,例子如下。
在这里插入图片描述
常量引用主要用来修饰形参,防止误操作改动实参数值。

int a = 10;
int &b = a;  //合法

int a = 10;
int &b = 10;  //不合法

int a = 10;
const int &b = 10;  //合法  相当于 int temp = 10; int &b = temp;

前面提到,引用其实是一个指针常量,因此当其作为函数形参传递的时候,如果在函数体中修改了形参,实参也会跟着变动,有时候为了防止函数中修改形参,要在引用前加上const。
可以看到,如果引用作为参数的时候,在函数内部修改了引用的值,调用函数后实参的值也跟着改变了。
在这里插入图片描述
在形参前面加上const后,如果函数体内部试图修改引用的值,编译器就直接报错了!
在这里插入图片描述


三、函数的高级应用

1.默认参数

可以给函数的形参设置默认值,在传实参的时候,没有传实参就使用默认参数,传了实参就覆盖掉默认参数值。
需要注意的是,如果函数参数中某个位置已经有了默认参数,那么从这个位置往后都必须有默认值。比如一个函数带三个参数,如果第二个参数设置了默认值,那么第三个参数也必须有默认值。
如果函数的参数中只有一个默认参数,那么这个参数就必须放在函数的最后一个位置。
在这里插入图片描述
如果函数声明有默认参数,函数实现就不能有默认参数;或者函数实现有默认参数,函数声明就不能有默认参数。总之两个中至多有一个有默认参数,否则会发生重复定义默认参数错误。 这样定义很容易理解,比如某个参数在函数声明的时候给定的默认值为10,函数实现的时候给了20,这个时候就出现了二义性,编译器不知道按照哪个默认参数来执行了。

//可以
int fun(int a,int b=20,int c=30);
int fun(int a,int b,int c)
{
	return a+b+c;
}
//可以
int fun(int a,int b,int c);
int fun(int a,int b=20,int c=30)
{
	return a+b+c;
}
//即使参数的默认值相同,函数声明和函数实现也不可以同时有
int fun(int a,int b=20,int c=30);
int fun(int a,int b=20,int c=30)
{
	return a+b+c;
}

2.占位参数

函数占位参数:C++中函数的列表里可以有占位参数,用来做占位,调用函数时必须填补该位置。
函数中占位参数只声明变量类型,而不给形参变量。占位参数也可以有默认参数。

void fun(int a,int)  //第二个int就是占位参数
{ 
	...
}
fun(10,20);   //函数调用

void fun(int a,int = 10)  //给占位参数设置默认值
{ 
	...
}
fun(10);   //函数调用
fun(10,20);  

3.函数重载

函数重载:函数名可以相同,提高复用性。
函数重载需满足的条件:同一个作用于下(全局);函数名相同;函数参数类型不同、或函数参数个数不同、或函数参数的顺序不同。
需要注意的是,函数的返回值不可以作为函数重载的条件
下面的代码就是函数重载的例子。

#include <iostream>
using namespace std;

void fun()
{
	cout<<"fun()"<<endl;
}

//以下两个函数参数个数相同,但参数类型不同
void fun(int a)
{
	cout<<"fun(int a)"<<endl;
}

void fun(double a)
{
	cout<<"fun(double a)"<<endl;
}

//以下两个函数参数个数相同,但参数顺序不同
void fun(int a,double b)
{
	cout<<"fun(int a,double b)"<<endl;
}

void fun(double a,int b)
{
	cout<<"fun(double a,int b)"<<endl;
}

int main()
{
	fun();
	fun(10);
	fun(10.0);
	fun(10,10.0);
	fun(10.0,10);

	system("pause");
	return 0;
}

上面程序运行后的结果如下图所示。
在这里插入图片描述
仅靠函数类型不同是无法完成函数重载的,像下面这样。

void fun()
{
	cout<<"fun()"<<endl;
}

int fun()
{
	cout<<"fun()"<<endl;
}

但是函数类型结合参数类型、参数个数、参数顺序可以实现函数重载。
在这里插入图片描述
引用作为函数参数重载时,需要注意参数类型前加const和不加const是可以重载成功的。 当函数参数类型前加了const后,函数调用的时候就需要传入常量值。
在这里插入图片描述
函数重载中应尽量避免默认参数的使用,如下面的函数重载例子,如果给默认参数的位置传入实参,则代码不会出错,而只传入一个值的时候,函数调用就会出现二义性,编译器不知道应该调用哪个函数了。

void fun(int a)
{
	cout<<"fun(int a)"<<endl;
}

void fun(int a,int b = 10)
{
	cout<<"fun(int a,int b = 10)"<<endl;
}

fun(10,20);  //合法
fun(10);  //不合法,函数调用出现了二义性

本文参考视频:
黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难

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

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

相关文章

力扣刷题-二叉树-二叉搜索树中的搜索

700 二叉搜索树中的搜索 给定二叉搜索树&#xff08;BST&#xff09;的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在&#xff0c;则返回 NULL。 例如&#xff0c; 在上述示例中&#xff0c;如果要找的值是 5&#x…

迟来的扫雷游戏

今天我们讲如何用C语言编写出一个简单扫雷&#xff0c;扫雷也算是一个比较原始的游戏了吧&#xff0c;那么我们今天就来实现他&#xff01; 首先我们要来缕一缕游戏框架 我们在代码中我们肯定会写许多函数来实现扫雷&#xff0c;那么我们为了简便看出游戏的运行逻辑&#xff0…

字节跳动 Spark 支持万卡模型推理实践

摘要&#xff1a;本文整理自字节跳动基础架构工程师刘畅和字节跳动机器学习系统工程师张永强在本次 CommunityOverCode Asia 2023 中的《字节跳动 Spark 支持万卡模型推理实践》主题演讲。 背景介绍 在云原生化的发展过程中 Kubernetes 由于其强大的生态构建能力和影响力&…

Consule安装与SpringBoot集成

Consule Consul 是由 HashiCorp 开发的一款软件工具&#xff0c;提供了一组功能&#xff0c;用于服务发现、配置管理和网络基础设施自动化。它旨在帮助组织管理现代分布式和微服务架构系统的复杂性。以下是Consul的一些关键方面和功能&#xff1a; 服务发现&#xff1a;Consul…

大数据 - Doris系列《二》- Doris安装(亲测成功版)

目录 &#x1f436;2.1 安装前准备 &#x1f959;1.设置系统最大文件打开句柄数 >启动一个程序的时候&#xff0c;打开文件的数量就是句柄数 &#x1f959;3.时钟同步 &#x1f959;4.关闭交换分区&#xff08;swap&#xff09; &#x1f436;2.2 安装FE &#x1f436…

seo分享:慎重使用蜘蛛池

其实要提高搜索引擎蜘蛛的来访次数&#xff0c;唯一的方法还是要通过网站本身的内容更新。频繁更新有质量的内容&#xff0c;才能够提高蜘蛛的来访次数。如果本身内容更新不多&#xff0c;外部引流的蜘蛛过多&#xff0c;最终发现没什么内容索引&#xff0c;蜘蛛来访的次数也会…

express+mongoDB开发入门教程之mongoose使用讲解

系列文章 node.js express框架开发入门教程 expressmongoDB开发入门教程之mongoDB安装expressmongoDB开发入门教程之mongoose使用讲解 文章目录 系列文章前言一、Mongoose是什么&#xff1f;二、Mongoose安装三、Mongoose在express项目中使用步骤一、连接mongoDB数据库步骤二、…

网络路由跟踪工具

随着企业网络需求的增长&#xff0c;组织发现监控和管理其网络基础设施变得越来越困难。网络管理员正在转向其他工具和资源&#xff0c;这些工具和资源可以使他们的工作更轻松一些&#xff0c;尤其是在故障排除方面。 目前&#xff0c;网络管理员主要使用简单、免费提供的实用…

C#中使用 async await TaskCompletionSource<T>实现异步逻辑同步写

Task、async 和 await 是 C# 中用于处理异步编程的关键概念。它们一起构成了异步编程的基础。 Task Task 是表示异步操作的抽象&#xff0c;它属于 System.Threading.Tasks 命名空间。Task 可以表示已经完成的任务、正在运行的任务或者尚未开始的任务。通过 Task&#xff0c;…

MySQL自定义时间间隔抽稀

MySQL自定义时间间隔抽稀 表设计数据如下按分钟抽稀按小时抽稀按天抽稀 表设计 create table monitor (tid varchar(255) not null,save_date datetime not null,tlevel decimal(10, 2) null,primary key (tid, save_date) );数据如下 按分钟抽稀 SELECT t2…

FLatten Transformer:聚焦式线性注意力模块

线性注意力将Softmax解耦为两个独立的函数&#xff0c;从而能够将注意力的计算顺序从(querykey)value调整为query(keyvalue)&#xff0c;使得总体的计算复杂度降低为线性。然而&#xff0c;目前的线性注意力方法要么性能明显不如Softmax注意力&#xff0c;并且可能涉及映射函数…

webapp下没有蓝点解决

解决方法&#xff1a; File->Project Structure 现在就是一个JavaWeb项目了。

华为云CES监控与飞书通知

华为云负载均衡连接数监控与飞书通知 在云服务的日常运维中&#xff0c;持续监控资源状态是保障系统稳定性的关键步骤之一。本文通过一个实际案例展示了如何使用华为云的Go SDK获取负载均衡器的连接数&#xff0c;并通过飞书Webhook发送通知到团队群组&#xff0c;以便运维人员…

2024 Nomachine 最简安装与使用指南

一、前言 二、Nomachine安装包的下载 1、Windows系统下Nomachine包的下载 2、Linux系统Nomachine的下载 &#xff08;1&#xff09;下载Nomachine安装包 &#xff08;2&#xff09;解压安装包 &#xff08;3&#xff09;添加权限 &#xff08;4&#xff09;下载安装包 三、在Wi…

基于GEC6818的点餐系统

本次项目开发环境&#xff1a;gec6818&#xff0c;QT5.14.2&#xff0c;SecureCRT。 所使用的相关技术&#xff1a;c/s架构&#xff0c;STL库&#xff0c;C封装&#xff0c;标准化代码编写 实现的功能&#xff1a;用户登录页面&#xff0c;食品分区在不同页面&#xff0c;用户…

2023海内外零知识证明学习资料汇总(二)(深入理解零知识证明篇)

工欲善其事,必先利其器 Web3开发中&#xff0c;各种工具、教程、社区、语言框架.。。。 种类繁多&#xff0c;是否有一个包罗万象的工具专注与Web3开发和相关资讯能毕其功于一役&#xff1f; 参见另一篇博文&#x1f449; 2024最全面且有知识深度的web3开发工具、web3学习项目…

Java中关键词strictfp有什么作用?

在Java中&#xff0c;关键词strictfp用于声明一个方法、类或接口是严格遵守浮点数计算规范的。 具体作用包括&#xff1a; 保证浮点数计算的结果在不同平台上是一致的&#xff0c;避免由于浮点数计算的不精确性导致的结果不确定性。 指定了严格的浮点数计算规则&#xff0c;禁…

【机器学习基础】DBSCAN

&#x1f680;个人主页&#xff1a;为梦而生~ 关注我一起学习吧&#xff01; &#x1f4a1;专栏&#xff1a;机器学习 欢迎订阅&#xff01;相对完整的机器学习基础教学&#xff01; ⭐特别提醒&#xff1a;针对机器学习&#xff0c;特别开始专栏&#xff1a;机器学习python实战…

springboot实现用户操作日志记录

springboot实现用户操作日志记录 简介&#xff1a;之前写了《aop实现日志持久化记录》一文&#xff0c;主要介绍自定义aop标注方法上&#xff0c;通过切面方法对用户操作插入mysql。思路正确但是实际操作上存在一些小问题&#xff0c;本文将从项目出发&#xff0c;对细节进行补…

vue3+vant4 移动端软键盘弹出 收起导致项目样式布局错乱解决方案,亲测有效!!

问题描述 最近在做vue3 H5的移动端项目 我用的是vue3vant4&#xff0c;然后在使用过程中发现 小米14手机在点击密码输入框软键盘弹出 时会导致项目布局整体向上移动 导致页面布局错乱。 原因分析&#xff1a; 在移动端软键盘弹出收起时&#xff0c;导致项目样式布局错乱的原因…