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

文章目录

  • 一、内存分区
  • 二、引用
  • 三、函数的高级应用
    • 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.mfbz.cn/a/292069.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

docker镜像仓库详解(Docker Registry)

本片文章主要是对docker的镜像仓库进行了详解。其中包含了一些常用了 docker 指令&#xff0c;通过举例进行详解。也详细解释了镜像仓库的工作机制和常见的镜像仓库。也实际拉去和运行了一些镜像。希望本篇文章会对你有所帮助&#xff01; 文章目录 一、什么是Docker Registry …

jQuery图片放大缩小旋转预览代码

jQuery图片放大缩小旋转预览代码-遇见你与你分享

基于SpringBoot的在线考试系统源码和论文

网络的广泛应用给生活带来了十分的便利。所以把在线考试管理与现在网络相结合&#xff0c;利用java技术建设在线考试系统&#xff0c;实现在线考试的信息化管理。则对于进一步提高在线考试管理发展&#xff0c;丰富在线考试管理经验能起到不少的促进作用。 在线考试系统能够通…

独立看门狗与窗口看门狗

一、简介 STM32F10xxx内置两个看门狗&#xff0c;提供了更高的安全性、时间的精确性和使用的灵活性。两个看门狗设备(独立看门狗和窗口看门狗)可用来检测和解决由软件错误引起的故障&#xff1b;当计数器达到给定的超时值时&#xff0c;触发一个中断(仅适用于窗口型看门狗)或产…

FindMy技术用于鼠标

鼠标是计算机的标准配置之一&#xff0c;其设计初衷是为了使计算机的操作更加简便快捷&#xff0c;减少用户在操作中的负担。用户可以通过移动鼠标&#xff0c;实现光标的精确移动&#xff0c;进而选择、拖拽、复制、粘贴等操作。这种操作方式&#xff0c;使得计算机的操作变得…

小程序测试和APP测试的区别

今天看了一下关于如何测试小程序的教学视频&#xff0c;里面讨论了一个很经典的面试题&#xff1a;小程序测试和APP测试的区别&#xff0c;包括在之前的面试过程中也确实是遇到过这个问题&#xff0c;所以这次打算把它记录下来&#xff0c;也算是知识巩固了。 首先从测试的内容…

2023年终总结,被裁员

在一个睡意朦胧的早上&#xff0c;我被闹钟惊醒&#xff0c;原来今天已经是2024年1月1日了&#xff0c;2023年平平无奇的结束了&#xff0c;唯一让我感触波深的事情是我在二月份的裁员名单里面。2024加油&#xff01;&#xff01;&#xff01; 工作上的总结 回顾2023&#xf…

本地监控jar包可视化性能数据

一、机器申请 二、maven项目jar打包 三、机器性能监控 1.jdk版本配置 本地下载的机器虽自带jdk&#xff0c;但是jdk版本过低&#xff0c;需重新安装jdk 参考&#xff1a; Linux系统安装JDK1.8 详细流程_linux安装jdk1.8-CSDN博客 2.jvm参数修改 需修改jvm堆内存 栈内存信…

Linux基础——进程初识(三)

1. 进程优先级 首先我们要知道&#xff0c;进程优先级是操作系统用来确定多个进程同时运行时&#xff0c;哪个进程会获得更多CPU时间片的相对重要性或优先级的评估。他和权限的区别在于权限决定了能不能访问资源&#xff0c;而优先级是在能访问资源的前提下&#xff0c;决定了…

Day7 vitest 之 vitest配置第三版

项目目录 runner Type: VitestRunnerConstructor Default: node, 当运行test的时候 benchmark,当运行bench测试的时候 功能 自定义测试运行程序的路径。 要求 应与自定义库运行程序一起使用。 如果您只是运行测试&#xff0c;则可能不需要这个。它主要由library作者使用 …

多线程实践项目

前言 前面几篇文章分别学习了多线程的基本知识和线程池使用&#xff0c;这篇则为项目实践和整理。 项目参考 选择了两个项目github地址&#xff0c;如果不方便下载可以下面留言评论私发。 1.马士兵老师的juc&#xff0c;讲述了多线程的基本知识线程讲解 2.基本的线程演示&am…

几种读nii图像方法的轴序比较

读 .nii / .nii.gz 图像并转成 numpy 可用 medpy.io、nibabel、itk、SimpleITK 几种方法&#xff0c;然而几种方法读出来的轴序有出入&#xff0c;本篇比较此几种方法。 Datum 所用数据来自 verse&#xff0c;经 iTomxy/data/verse/preprocess.py 预处理&#xff0c;朝向和轴…

【VTK三维重建-体绘制】第五期 vtkLODProp3D

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ&#xff1a;870202403 前言 本文分享VTK中体绘制中的vtkLODProp3D对象&#xff0c;希望对各位小伙伴有所帮助&#xff01; 感谢各位小伙伴的点赞关注&#xff0c;小易会继续努力分享&#xff0c;一起进步&#xff01; 你的点赞…

【数据挖掘】基于 LightGBM 的系统访问风险识别(附源码)

基于 LightGBM 的系统访问风险识别 文章目录 基于 LightGBM 的系统访问风险识别一、课题来源二、任务描述三、课题背景四、数据获取分析及说明&#xff08;1&#xff09;登录https://www.datafountain.cn并获取相关数据&#xff08;2&#xff09;数据集文件说明&#xff08;3&a…

好代码网同款wordpress主题,适合搭建资源分享类网站,自带五六百的精品资源数据

代码简介&#xff1a; 好代码资源网是个还不错的资源分享类网站&#xff0c;基于wordpress搭建的。它的主题看起来还是不错的。这里分享一下这个网站的主题包。说是主题包&#xff0c;其实就是整站打包的&#xff0c;集成了主题&#xff08;wordpress美化主题包几个插件&#…

从vue小白到高手,从一个内容管理网站开始实战开发第六天,登录功能后台功能设计--API项目中的登录实现(一)

从vue小白到高手,从一个内容管理网站开始实战开发第五天,登录功能后台功能设计--数据库与API项目-CSDN博客文章浏览阅读348次,点赞9次,收藏7次。本次文章主要讲了开发后台API项目给前台vue调用的话,需要使用的数据库并新建数据库和表、安装开发工具、如何创建API项目以及A…

05-微服务-RabbitMQ-概述

RabbitMQ 1.初识MQ 1.1.同步和异步通讯 微服务间通讯有同步和异步两种方式&#xff1a; 同步通讯&#xff1a;就像打电话&#xff0c;需要实时响应。 异步通讯&#xff1a;就像发邮件&#xff0c;不需要马上回复。 两种方式各有优劣&#xff0c;打电话可以立即得到响应&am…

深入解析美颜SDK:绿幕抠图功能的算法原理

当下&#xff0c;美颜SDK绿幕抠图功能成为许多应用中不可或缺的一环。本文将深入解析美颜SDK中绿幕抠图功能的算法原理&#xff0c;揭示其背后的技术奥秘。 一、什么是美颜SDK绿幕抠图&#xff1f; 美颜SDK的绿幕抠图功能是一种通过计算机视觉技术&#xff0c;将视频或图像中…

十六:爬虫-验证码与字体反爬

一&#xff1a;验证码 验证码&#xff08;CAPTCHA&#xff09;是一种计算机程序设计技术&#xff0c;用于确定用户是人类而不是机器。它通常表现为一种图像或声音&#xff0c;要求用户在输入框中输入正确的文本或数字来证明自己是人类。因为机器人和计算机程序无法像人类一样理…

《深入理解C++11:C++11新特性解析与应用》笔记八

第八章 融入实际应用 8.1 对齐支持 8.1.1 数据对齐 c可以通过sizeof查询数据的长度&#xff0c;但是没有对对齐方式有关的查询或者设定进行标准化。c11标准定义的alignof函数可以查看数据的对齐方式。 现在的计算机通常会支持许多向量指令&#xff0c;4组8字节的浮点数据&a…
最新文章