C++核心编程之内存分区模型,引用,函数提高

news2024/10/6 10:33:54

1,类型分区模型

c++程序在执行中,将内存大方向划分为4个区域

1,代码区:存放函数体的二进制代码,由操作系统进行管理的

2,全局区:存放全局变量和静态变量以及常量

3,栈区:由编译器自动分配释放,存放函数的参数值,局部变量等

4,堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收

内存四区的意义:

不同区域存放的数据,赋予不同的声明周期,给我们更大的灵活编程

1.1  程序运行前

在程序编译后,生成exe可执行程序,未执行程序前分两个区域:

代码区:

存放CPU执行的机器指令

代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可

代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令

全局区:

全局变量和静态变量存放于此

全局区还包含了常量区,字符串常量和其他常量也存放于此

该区域的数据在程序结束后由操作系统操作

代码展示:

#include<iostream>
using namespace std;

//全局变量
int g_a = 10;
int g_b = 10;

int main()
{
	//全局区

	//全局变量,静态变量,常量

	//创建普通局部变量
	int a = 10;
	int b = 10;
	cout << "局部变量a的地址:" << &a << endl;
	cout << "局部变量b的地址:" << &b << endl;
	cout << endl;

	cout << "全局变量g_a的地址:" << &g_a << endl;
	cout << "全局变量g_b的地址:" << &g_b << endl;
	cout << endl;

	//静态变量  在普通变量前加static,属于静态变量
	static int s_a = 10;
	static int s_b = 10;
	cout << "静态变量s_a的地址:" << &s_a << endl;
	cout << "静态变量s_b的地址:" << &s_b << endl;
	cout << endl;

	//常量
	//字符串常量
	cout << "字符串常量的地址为:" << &"hello world" << endl;
	cout << endl;

	//const修饰的变量
	//const修饰的全局变量
	const int c_g_a = 10;
	const int c_g_b = 10;
	cout << "全局常量 c_g_a的地址:" << &c_g_a << endl;
	cout << "全局常量 c_g_b的地址:" << &c_g_b << endl;
	cout << endl;

	//const修饰的局部变量
	const int c_l_a = 10;
	const int c_l_b = 10;
	cout << "全局常量 c_g_a的地址:" << &c_l_a << endl;
	cout << "全局常量 c_g_b的地址:" << &c_l_b << endl;
	cout << endl;

	system("pause");
	return 0;
}


总结:

c++中程序运行前分为全局区和代码区

代码区的特点是共享和只读

全局区中存放全局变量,静态变量,常量

常量区中存放const修饰的全局变量和字符串变量 

1.2  程序运行后

栈区:由编译器自动分配释放,存放函数的参数值,局部变量等

注意:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放

int* func()
{
	//利用new关键字 可以将数据开辟到堆区
	//指针,本质也是局部变量,放在栈区,指针保存的数据是放在栈区
	int* a = new int(10);
	return a;
}
int main()
{
	//在堆区开辟数据
	int* p = func();

	cout << "第一个:" << *p << endl;//每一次都会保存正确的数据
	cout << "第二个:" << *p << endl;
	cout << "第二个:" << *p << endl;
	cout << "第二个:" << *p << endl;
	cout << "第二个:" << *p << endl;
	cout << "第二个:" << *p << endl;
	cout << "第二个:" << *p << endl;
	system("pause");
	return 0;
}

堆区:

由程序员分配释放,若 程序员不释放,程序结束时由操作系统释放

在C++中主要利用new在堆区开辟内存

示例:

int* func()
{
	int* a = new int(10);
	return a;
}
int main()
{
	int* p = func();

	cout << "第一个:" << *p << endl;//每一次都会保存正确的数据
	cout << "第二个:" << *p << endl;
	cout << "第二个:" << *p << endl;
	cout << "第二个:" << *p << endl;
	cout << "第二个:" << *p << endl;
	cout << "第二个:" << *p << endl;
	cout << "第二个:" << *p << endl;
	system("pause");
	return 0;
}

 

1.3  new操作符

C++中利用new操作符在堆区开辟数据

堆区开辟的数据,由程序员手动开辟,释放利用操作符delete

语法: new  数据类型

利用new创建的数据,会返回该数据对应的类型的指针

示例1:基本语法:

#include<iostream>
using namespace std;
//1,new的基本语法
int* func()
{
	//在堆区创建整型数据
	//new返回是 该数据类型的指针
	int* a = new int(10);
	return a;
}

int main()
{
	int* p = func();
	cout << *p << endl;
	cout << *p << endl;
	cout << *p << endl;

	//delete p;
	//堆区的数据 由程序员管理开辟,程序员管理释放
	//如果向释放堆区的数据,利用关键字 delete
	cout << *p << endl;
	system("pause");
	return 0;
}

 

示例2:开辟数组 

//2,开辟数组
int main()
{
	int* arr = new int[10];
	for (int i = 0; i < 10; i++)
	{
		arr[i] = i + 100;
	}
	for (int i = 0; i < 10; i++)
	{
		cout << arr[i] << endl;
	}
	delete[] arr;//释放数组 delete后加[]
	//int* arr = new int[10];
	/*for (int i = 0; i < 10; i++)//释放后不能再次使用
	{
		arr[i] = i + 100;
	}
	for (int i = 0; i < 10; i++)
	{
		cout << arr[i] << endl;
	}*/
	system("pause");
	return 0;
}

 

2,引用

2.1 引用的基本使用

作用:给变量起别名

语法:数据类型  &别名 = 原名;

示例: 

#include<iostream>
using namespace std;
int main()
{
	//引用的基本语法
	//数据类型  &别名 = 原名
	int a = 10;
	//创建引用
	int& b = a;

	cout << "a=" << a << endl;
	cout << "b=" << b << endl;

	b = 100;

	cout << "a=" << a << endl;
	cout << "b=" << b << endl;

	system("pause");
	return 0;
}

 

2.2 引用的注意事项

引用必须初始化

引用在初始化后,不可以改变

int main()
{
	int a = 10;
	int b = 10;
	//int& c;//报错,引用必须初始化
	int& c=a;//一旦初始化后,就不可以更改
	c = b;//这是赋值操作,不是更改引用
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
	cout << "c=" << c << endl;
	system("pause");
	return 0;
}

2.3 引用做函数参数

作用:函数传参是,可以利用引用的技术让形参修饰实参

优点:可以简化指针修饰实参

示例:

//引用做函数参数
//1,值传递
void Swap01(int a,int b)
{
	int temp = a;
	a = b;
	b = temp;
	cout << "a= " << a << endl;
	cout << "b= " << b << endl;
	cout << endl;
}
//2,地址传递
void Swap02(int* a, int* b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
	cout << "a= " << *a << endl;
	cout << "b= " << *b << endl;
	cout << endl;
}

//3,引用传递
void Swap03(int& a, int& b)
{
	int temp = a;
	a = b;
	b = temp;
	cout << "a= " << a << endl;
	cout << "b= " << b << endl;
	cout << endl;
}
int main()
{
	Swap01(10,20);//值传递,形参不会修饰实参
	int a = 30;
	int b = 40;
	cout << "a= " << a << endl;
	cout << "b= " << b << endl;
	cout << endl;

	Swap02(&a,&b);//地址传递,形参会修饰实参
	cout << "a= " << a << endl;
	cout << "b= " << b << endl;
	cout << endl;

	a = 50;
	b = 60;
	Swap03(a, b);//引用传递,形参会修饰实参
	cout << "a= " << a << endl;
	cout << "b= " << b << endl;
	cout << endl;

	system("pause");
	return 0;
}

总结:通过引用参数产生的效果同按地址传递是一样的。

           引用的语法更清楚 

2.4 引用做函数返回值

作用:引用时可以作为函数的返回值存在的

注意:不要返回局部变量引用

用法:函数调用作为左值

示例1:

1,不要返回局部变量的引用

int& test01()
{
	int a = 10; //局部变量放在四区中的栈区
	return a;
}

int main()
{
	int &ref = test01();

	cout << "ref= " << ref << endl;//第一次结果正确,是因为编译器做了保留
	cout << "ref= " << ref << endl;//第二次结果错误,是因为a的内存已经释放

	system("pause");
	return 0;
}

示例二: 

//函数的调用可以作为左值
int& test02()
{
	static int a = 10; //静态变量存放在全局区,全局区上的数据在程序结束后系统释放
	return a;
}

int main()
{
	int& ref = test02();

	cout << "ref= " << ref << endl;
	cout << "ref= " << ref << endl;
	
	test02() = 1000;//如果函数的返回值是引用,这个函数调用可以作为左值
	cout << "ref= " << ref << endl;
	cout << "ref= " << ref << endl;

	system("pause");
	return 0;
}

2.5 引用的本质

本质:引用的本质在c++内部实现是一个指针常量

示例:

//引用的本质
//发现是引用,转换为int* const ref = &a;
void func(int& ref)
{
	ref = 100;//ref是引用,转换为*ref = 100;
}

int main()
{
	//自动转化为int* const ref = &a;指针常量是指针指向不可改,也说明为什么引用不可以更改
	int a = 10;
	int& ref = a;
	ref = 20;//内部发现ref是引用,自动帮我们转换为*ref=20;

	cout << "a= " << a << endl;
	cout << "ref= " << ref << endl;

	func(a);
	cout << "a= " << a << endl;
	cout << "ref= " << ref << endl;
	system("pause");
	return 0;
}

结论:C++推荐引用技术,因为语法方便,引用本质是常量指针 

2.6 常量引用

作用:常量引用主要用来修饰形参,防止误操作

在函数形参列表中,我们可以加const修饰形参,防止形参改变实参

示例:

//引用使用的场景,通常用来修饰形参
void showValue(const int& v)
{
	//v += 10;
	cout <<"v= "<< v << endl;
}
int main()
{
	//int& ref = 10;//引用本身需要一个合法的内存空间,因此这行错误
	//加入const就可以了,编译器做了优化代码,int temo = 10;const int& ref = temp;
	const int& ref = 10;
	cout << "ref= "<<ref << endl;

	//ref=100;//加入const后不可以修改变量
	int a = 10;

	//函数中利用常量引用防止误操作修改实参
	showValue(a);

	system("pause");
	return 0;
}

3,函数提高 

3.1 函数默认参数

在C++中,函数的形参列表中的形参是由默认值的。

语法:返回值类型  函数名 (参数 = 默认值){}

示例1:

#include<iostream>
using namespace std;
int func1(int a, int b, int c)
{
	return a + b + c;
}

//如果我们积极传入数据,就用自己的数据,如果没有,那就用默认值
//b未传入数据,则使用默认值
int func2(int a, int b = 20, int c = 30)
{
	return a + b + c;
}

//都传入了数据,那就用自己的数据
int func3(int a, int b, int c)
{
	return a + b + c;
}

int main()
{
	cout << "func1()的值" << endl;
	cout << func1(10, 20, 30) << endl;
	cout << endl;

	cout << "func2()的值" << endl;
	cout << func2(10, 30) << endl;
	cout << endl;

	cout << "func3()的值" << endl;
	cout << func1(30, 40, 50) << endl;
	cout << endl;

	system("pause");
	return 0;

示例2:

 

//注意事项:
//1,如果某个位置已经有了默认参数,那么从那个位置往后,从左到右必须都有默认值
//int func1(int a=10, int b, int c,int d)//错误
//{
//	return a + b + c;
//}

//2,如果函数声明由默认参数,函数实现就不能由默认参数
//int func2(int a=10, int b=10);
//声明和实现都能有一个默认参数
int func2(int a=10, int b=20)
{
	return a + b;
}

int main()
{
	cout << func2(10) << endl;
	return 0;
}

3.2函数占位参数

C++中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置

语法:返回值类型 函数名  (函数类型){ }

在现阶段函数的占位参数存在意义不大,但是后面的课程中会用到该技术

示例:

//函数占位参数,占位参数也可以有默认参数
void func(int a, int)
{
	cout << "this is func" << endl;
}
int main()
{
	func(10, 10);//占位参数必须填补

	system("pause");

}

3.3 函数重载

void func()
{
	cout << "func的调用" << endl;
}

void func(int a)
{
	cout << "func的调用" << endl;
}

void func(double a)
{
	cout << "func的调用" << endl;
}

//函数返回值不能作为函数重载条件
//int func(double a,int b)
//{
//	cout << " func(double a,int b)" << endl;
//}

int main()
{
	//func()
	func(10);
	func(3.14);
}

作用:函数名可以相同,提高复用性

3.3.1函数重载满足条件:

1,同一个作用域下

2,函数名相同

3,函数参数类型不同或者个数不同或者顺序不同

注意:函数的返回值不可以作为函数重载的条件

void func()
{
	cout << "func的调用" << endl;
}

void func(int a)
{
	cout << "func的调用" << endl;
}

void func(double a)
{
	cout << "func的调用" << endl;
}

//函数返回值不能作为函数重载条件
//int func(double a,int b)
//{
//	cout << " func(double a,int b)" << endl;
//}

int main()
{
	//func()
	func(10);
	func(3.14);
}

3.3.2  函数重载注意事项

1,引用作为重载条件

2,函数重载碰到函数默认条件

示例:

// 函数重载注意事项
//1,引用作为重载条件
void func(int& a)
{
	cout << "func(int &a)的调用" << endl;
}

void func(const int& a)
{
	cout << "func(int &a)的调用" << endl;
}
//2,函数重载碰到函数默认条件
void func2(int a, int b = 10)
{
	cout << "func2(int a,int b = 10)调用" << endl;
}

void func2(int a)
{
	cout << "func2(int a)调用" << endl;
}

int main()
{
	int a = 10;
	//func2(a);//调用无const
	//func2(10);//调用有const

	//func2(10);//碰到默认参数产生歧义,需要避免

	system("pause");
	return 0;
}

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

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

相关文章

【学习笔记】java项目:黑马头条(day01)

文章目录 环境搭建、SpringCloud微服务(注册发现、服务调用、网关)1)课程对比2)项目概述2.1)能让你收获什么2.2)项目课程大纲2.3)项目概述2.4)项目术语2.5)业务说明 3)技术栈4)nacos环境搭建4.1)虚拟机镜像准备4.2)nacos安装 5)初始工程搭建5.1)环境准备5.2)主体结构 6)登录6.1…

Openfeign+Ribbon+Hystrix断路器(服务降级)

热部署对于Hystrix的热不是不是很明显 所以最好修改代码之后重启服务 简介 在微服务架构中存在多个可直接调用的服务,这些服务若在调用时出现故障会导致连锁效应,也就是可能让整个系统变得不可用,这种情况我们称之为服务雪崩效应. 服务雪崩效应通常发生在微服务架构中&…

应用监控 eBPF 版:实现 Golang 微服务的无侵入应用监控

作者&#xff1a;古琦 在现代软件架构中&#xff0c;微服务已成为构建可扩展和灵活应用程序的流行方式。每个微服务负责应用程序的一部分功能&#xff0c;它们共同工作以提供完整的服务。由于微服务架构的分散特性&#xff0c;监控变得至关重要&#xff0c;有效的微服务监控是…

缺陷检测:使用PatchCore训练自己的数据集

文章目录 前期准备两种方法 演示运行结果 代码详解见缺陷检测–PatchCore的代码解读 前期准备 必须包含有训练图片&#xff08;无缺陷图片&#xff09;、测试图片&#xff08;缺陷图片&#xff09;和ground_truth&#xff0c;并且ground_truth必须与对应图片的名称相同。 本文…

python_读取txt文件绘制多条曲线II

从给定的列表中来匹配txt文件对应列的数据&#xff1b; import matplotlib.pyplot as plt import re from datetime import datetime from pylab import mplmpl.rcParams["font.sans-serif"] ["SimHei"] # 设置显示中文字体 mpl.rcParams["axes.un…

STM32用标准库做定时器定时1秒更新OLED的计数值(Proteus仿真)

首先新建proteus工程&#xff0c;绘制电路图&#xff1a; 然后赋值我之前文章中提到的文件夹OLED屏幕显示&#xff1a;&#xff08;没有的自己去那篇文章下载去&#xff09; 然后进入文件夹&#xff1a; 新建两个文件在Mycode文件夹中&#xff1a; 文件关系如下&#xff1a; 新…

lowcode-engine接入编辑器

https://lowcode-engine.cn/site/docs/guide/create/useEditor 方案1 pnpm init pnpm add "alilc/create-elementlatest"pnpm create "alilc/element" editor-project-name选择编辑器 进入执行pnpm install命令安装包 pnpm start报错 pnpm add &qu…

springboot-异步、定时、邮件任务

一、异步任务 1、创建项目 2、创建一个service包 3、创建一个类AsyncService 异步处理还是非常常用的&#xff0c;比如我们在网站上发送邮件&#xff0c;后台会去发送邮件&#xff0c;此时前台会造成响应不动&#xff0c;直到邮件发送完毕&#xff0c;响应才会成功&#xff…

高校的虚拟仿真实训室为何要创建数字人实训室?

随着教育信息化、数字化的不断发展&#xff0c;虚拟仿真实训室不再仅限于vr虚拟仿真实训室&#xff0c;数字人实训室也逐步应用于教育领域。 高校虚拟仿真实训室创建数字人实训室课堂&#xff0c;具有两大作用&#xff1a; 1.获得隐形实践知识 在虚拟仿真实训室环境下&#xf…

2024Java开发现状分析,字节java面试题

1. 前言 最近面试了几家公司&#xff0c;体验了一下电话面试和今年刚火起来的视频面试&#xff0c; 虽然之前就有一些公司会先通过电话面试的形式先评估下候选人的能力水平&#xff0c;但好像不多&#xff0c;至少我以前的面试形式100%都是现场面试。 面试过程中&#xff0c…

QT和OPENGL安装和集成

1.QT安装 1.1官网下载&#xff1a; 网址&#xff1a;https://download.qt.io/archive/qt/ 1.2 开始安装 点击运行 首先注册sign up 然后Login in 选择安装目录 改为D盘&#xff1a; 选择安装项&#xff1a; 准备安装 开始安装&#xff1a; 安装完成&#xff1a; 1.3测试 …

小白如何选择阿里云服务器配置?小白不怕

阿里云服务器配置怎么选择&#xff1f;CPU内存、公网带宽和系统盘怎么选择&#xff1f;个人开发者或中小企业选择轻量应用服务器、ECS经济型e实例&#xff0c;企业用户选择ECS通用算力型u1云服务器、ECS计算型c7、通用型g7云服务器&#xff0c;阿里云服务器网aliyunfuwuqi.com整…

第十五届蓝桥杯青少组STEMA测评SPIKE初级真题试卷 2024年1月

第十五届蓝桥杯青少组STEMA测评SPIKE初级真题试卷 2024年1月 ​​​​​​​ 来自&#xff1a;6547网 http://www.6547.cn/doc/vywur8eics

2024年政府工作报告,这些重点网安人应格外注意!

2024年政府工作报告&#xff0c;制定支持数字经济高质量发展政策&#xff0c;积极推进数字产业化、产业数字化&#xff0c;促进数字技术和实体经济深度融合。深化大数据、人工智能等研发应用&#xff0c;开展“人工智能”行动&#xff0c;打造具有国际竞争力的数字产业集群。作…

算法沉淀——贪心算法一(leetcode真题剖析)

算法沉淀——贪心算法一 01.柠檬水找零02.将数组和减半的最少操作次数03.最大数04.摆动序列 贪心算法&#xff08;Greedy Algorithm&#xff09;是一种基于贪心策略的优化算法&#xff0c;它通常用于求解最优化问题&#xff0c;每一步都选择当前状态下的最优解&#xff0c;以期…

如何提取二维码的链接?快速获取二维码链接的方法

如何提取二维码的链接&#xff1f;现在生活中有各种各样的二维码图片&#xff0c;扫码后可以展示不同内容&#xff0c;比如文本、音频、视频、文件、图片等等&#xff0c;都可以制作二维码图片来展示。但是在某些特殊情况下&#xff0c;需要将二维码转链接之后&#xff0c;通过…

使用Python访问Phoenix

需求分析 理解Phoenix的原理及应用场景&#xff0c;理解Thrift的原理及操作&#xff0c;掌握Python如何访问操作HBase。 系统实现 实验流程分析&#xff1a; 开启HBase集群 在Phoenix上创建表 启动Thrift服务 实现Python访问HBase 关闭启动的服务 开启HBase集群&#…

【软考高项】【论文专题】- 3 - 论文写作方法

目录 1、 论文构思 2、 论文背景 论点 收尾的写作 2.1 一般正文的布局 2.2 论文结构 2.2.1 结构一&#xff1a;万能通用结构 2.2.2 结构二 2.2.3 结构三 2.3 论文内容写作 2.3.1 撰写项目背景 2.3.2 撰写理论知识点应用 2.2.3 撰写经验总结(项目收尾部分) 2.3 撰…

FPGA 的 DSP:Verilog 中的简单 FIR 滤波器

本项目介绍如何用 Verilog 实现一个带有预生成系数的简单 FIR 滤波器。 Things used in this project 、 Story 简陋的 FIR 滤波器是 FPGA 数字信号处理中最基本的构建模块之一&#xff0c;因此了解如何利用给定的抽头数和相应的系数值组装一个基本模块非常重要。因此&#xf…

学生信息管理展示-h5版(uniapp+springboot+vue)

记录一下做的第一个完整的h5业务。 一、登录 二、个人中心 三、首页&#xff08;管理员&#xff09; 四、首页&#xff08;学生&#xff09; 五、视频展示 学生信息管理展示&#xff08;h5&#xff09;完整版