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

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;//堆区的数据 由程序员管理开辟,程序员管理释放//如果向释放堆区的数据,利用关键字 deletecout << *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.rhkb.cn/news/271905.html

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

相关文章

【性能测试】Jmeter性能压测-阶梯式/波浪式场景总结(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、阶梯式场景&am…

IDEA中四款代码补全的插件

说明&#xff1a;本文介绍四款IDEA中代码补全的插件及使用感受&#xff0c;插件如下&#xff1a; 以下插件都在2023.2版本的IDEA中安装使用的&#xff0c;旧版本IDEA可能无法使用。 Tabnine 在IDEA的插件商店中安装&#xff0c;官网&#xff08;https://www.tabnine.com/&…

ai智能写作软件推荐,ai一键生成作文

很多小伙伴们都觉得写作是一件让人头痛的事情。因为不仅要让自己的文字流畅有条理&#xff0c;还需要通过一些修辞手法来使文章更加生动有趣。市场上不断涌现出各种各样的AI人工智能原创文章写作平台&#xff0c;哪些才好用&#xff0c;才是适合自己的呢&#xff1f; 爱制作ai …

Z Potentials | 星爵,他的征途不止向量数据库

纵观过去几十年的科技发展史&#xff0c;每一代新的技术架构的出现往往都伴随着新的数据范式的出现&#xff0c;也催生了多家百亿到千亿美金数据平台的诞生。如果说 2023 年科技领域的关键词是 LLM&#xff0c;那么数据库领域的关键词一定非向量数据库莫属。向量数据库是一种专…

Redis核心数据结构之字典(二)

字典 解决键冲突 当有两个或以上数量的键被分配到了一个哈希表数组的同一个索引上面&#xff0c;我们称这些键发生了冲突(collision)。 Redis的哈希表使用链地址法(separate chaining)来解决键冲突&#xff0c;每个哈希表节点都有一个next指针&#xff0c;多个哈希表节点可以…

egg如何写单元测试

优秀的代码需要有单元测试进行质量保证&#xff0c;每个测试用例都给应用的稳定性提供了一层保障。 测试目录结构 我们约定 test 目录为存放所有测试脚本的目录&#xff0c;测试所使用到的 fixtures 和相关辅助脚本都应该放在此目录下。 测试文件的目录和我们需要测试的文件目…

#QT(智能家居界面-界面切换)

1.IDE&#xff1a;QTCreator 2.实验 3.记录 &#xff08;1&#xff09;创建一个新界面&#xff08;UI界面&#xff09; &#xff08;2&#xff09;可以看到新加入一个ui文件&#xff0c;双击打开&#xff0c;设置窗口大小与登录界面一致 &#xff08;3&#xff09;加入几个PUS…

【NR 定位】3GPP NR Positioning 5G定位标准解读(一)

目录 前言 1. 3GPP规划下的5G技术演进 2. 5G NR定位技术的发展 2.1 Rel-16首次对基于5G的定位技术进行标准化 2.2 Rel-17进一步提升5G定位技术的性能 3. Rel-18 关于5G定位技术的新方向、新进展 3.1 Sidelink高精度定位功能 3.2 针对上述不同用例&#xff0c;3GPP考虑按…

力扣经典题目解析--反转链表

原题地址: . - 力扣&#xff08;LeetCode&#xff09; 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1] 题目解析 链表&#xff08;Linked List&…

【Unity】ABB CRB 15000 外部引导运动

一、RobotStudio控制器的文件系统和配置参数 HOME&#xff1a;控制器文件系统的根目录或起始点。配置&#xff1a;机器人控制器的配置设置和参数。外件信息&#xff1a;连接到机器人的外部组件的信息。I/O 系统&#xff1a;输入/输出系统&#xff0c;管理机器人和外部设备之间的…

UNIapp实现局域网内在线升级

首先是UNIapp 生成apk 用Hbuilder 进行打包 可以从网站https://www.yunedit.com/reg?gotocert 使用自有证书&#xff0c;目测比直接使用云证书要快一些。 发布apk 网站 用IIS发布即可 注意事项中记录如下内容 第一、需要在 iis 的MiMe 中添加apk 的格式&#xff0c;否则无法…

JavaWeb-MyBatis(上)

学完项目管理工具Maven后&#xff0c;继续学习MyBatis。我们都知道&#xff0c;JDBC是一个与数据库连接相关的API&#xff0c;最开始学习数据库连接都是从JDBC开始学起&#xff0c;但是其也有缺点&#xff0c;比如硬编码和操作繁琐等等。而今天学习的MyBatis就是专门为简化JDBC…

论文目录3:大模型时代(2023+)

1 instruction tuning & in context learning 论文名称来源主要内容Finetuned Language Models Are Zero-Shot Learners2021 机器学习笔记&#xff1a;李宏毅ChatGPT Finetune VS Prompt_UQI-LIUWJ的博客-CSDN博客 早期做instruction tuning的work MetaICL: Learning to …

K线实战分析系列之十八:十字线——判断行情顶部的有效信号

K线实战分析系列之十八&#xff1a;十字线——判断行情顶部的有效信号 一、十字线二、十字线总结三、三种特殊十字线四、长腿十字线五、墓碑十字线六、蜻蜓十字线七、特殊十字线总结 一、十字线 重要的反转信号 幅度较大的下跌&#xff0c;出现一根十字线&#xff0c;正好是在…

力扣刷题Days13-101对称二叉树(js)

目录 1,题目 2&#xff0c;代码 2.1递归思想 2.2队列--迭代思想 3&#xff0c;学习与总结 1,题目 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 2&#xff0c;代码 2.1递归思想 return dfs(left.left, right.right) && dfs(left.right, right.l…

Go-知识struct

Go-知识struct 1. struct 的定义1.1 定义字段1.2 定义方法 2. struct的复用3. 方法受体4. 字段标签4.1 Tag是Struct的一部分4.2 Tag 的约定4.3 Tag 的获取 githupio地址&#xff1a;https://a18792721831.github.io/ 1. struct 的定义 Go 语言的struct与Java中的class类似&am…

局域网管理工具

每个组织的业务运营方法都是独一无二的&#xff0c;其网络基础设施也是如此&#xff0c;由于随着超融合基础设施等新计算技术的发展&#xff0c;局域网变得越来越复杂&#xff0c;因此局域网管理也应该如此&#xff0c;组织需要量身定制的局域网管理解决方案&#xff0c;这些解…

【C++】浅谈 vector 迭代器失效 深拷贝问题

目录 前言 一、底层空间改变 【错误版本1】 &#x1f31f;【解答】正确版本 ​ 【错误版本2】 &#x1f31f;【解答】正确版本 二、指定位置元素的删除操作--erase 【错误版本1】 &#x1f31f;【解答】 【错误版本2】 &#x1f31f;【解答】 三、深拷贝问题 前言 迭…

10 事务控制

文章目录 事务控制事务概述事务操作事务四大特性事务隔离级别 事务控制 事务概述 MySQL 事务主要用于处理操作量大&#xff0c;复杂度高的数据。比如说&#xff0c;在人员管理系统中&#xff0c;你删除一个人员&#xff0c;既需要删除人员的基本资料&#xff0c;也要删除和该…

探讨2024年AI辅助研发的趋势

一、引言 随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已经成为当今时代最具变革性的技术之一。AI的广泛应用正在重塑各行各业&#xff0c;其中&#xff0c;AI辅助研发作为科技和工业领域的一大创新热点&#xff0c;正引领着研发模式的深刻变革。从医药…