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.hqwc.cn/news/513524.html

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

相关文章

基于SSM的学科竞赛管理系统。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的学科竞赛管理系统。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring SpringMvcMybatisVueLayuiElemen…

MP2494图纸 国产替代型号SC72001宽工作输入电压范围:4.5V 至 80V

MP2494 是一款单片降压开关变换器。它在宽输入范围内可实现 2A 连续输出电流&#xff0c;具有出色的负载和线性调整率。其控制良好的开关沿降低了 EMI 干扰。故障保护功能包括逐周期限流保护和过温关断保护。MP2494 最大限度地减少了现有标准外部元器件的使用。MP2494采用SOIC8…

win系统如何同时安装MySQL5和MySQL8

win系统如何同时安装MySQL5和MySQL8 文章目录 win系统如何同时安装MySQL5和MySQL81、准备好两种版本的数据库2、下载后解压到你指定的目录3、手动配置安装MySQL5和8安装MySQL53.1创建my.ini文件3.2生成data文件夹 安装MySQL83.1创建my.ini文件3.2生成data文件夹 4、配置环境变量…

面试高频率问答题目

索引&#xff1a; 主键索引&#xff1a;表的id &#xff08;唯一 且 不能为空&#xff09; 唯一索引&#xff1a;表User 假设有account 字段 &#xff0c;用户名不重复 &#xff08;唯一 可以为空&#xff09; 复合索引&#xff1a;where() 的条件 用户名&#xff0c;密码 …

计算机组成原理----数据的表示和运算

一&#xff1a;进位计数制 1、进制 B&#xff1a;二进制&#xff1a;0-1 逢二进一、借一当二 O&#xff1a;八进制&#xff1a;0-7 逢八进一 D&#xff1a;十进制&#xff1a;0-9 逢十进一 H&#xff1a;十六进制&#xff1a;0-9、A-F 逢十六进一 r进制2 2、…

Cohere

文章目录 关于 cohere公司介绍目标&#xff1a;构建大模型基础设施产品商业模式 API 使用基于 Cohere AI 实现语义搜索 关于 cohere PYPI : https://pypi.org/project/cohere官网 : https://cohere.comgithub : https://github.com/cohere-ai/cohere-python文档&#xff1a;ht…

【2024】vue-router和pinia的配置使用

目录 vue-routerpiniavue-routerpinia进阶用法---动态路由 有同学在项目初始化后没有下载vue-router和pinia&#xff0c;下面开始&#xff1a; vue-router npm install vue-router然后在src目录下创建文件夹router&#xff0c;以及下面的index.ts文件&#xff1a; 写进下面的…

python--产品篇--游戏-坦克

文章目录 准备代码main.pycfg.py 效果 准备 下载 代码 main.py import os import cfg import pygame from modules import *主函数 def main(cfg):# 游戏初始化pygame.init()pygame.mixer.init()screen pygame.display.set_mode((cfg.WIDTH, cfg.HEIGHT))pygame.display.…

CHI协议学习

原始文档&#xff1a;https://developer.arm.com/documentation/102407/0100/?langen CHI 总线拓扑结构 CHI总线拓扑是实现自定义的&#xff0c;可以是RING/MESH/CROSSBAR的类型&#xff1b; RING 一般适用于中等规模芯片MESH 一般适用于大规模芯片CROSSBAR 一般适用于小规模…

工具函数模板题(蓝桥杯 C++ 代码 注解)

目录 一、Vector容器&#xff1a; 二、Queue队列 三、Map映射 四、题目&#xff08;快递分拣 vector&#xff09;&#xff1a; 代码&#xff1a; 五、题目&#xff08;CLZ银行问题 queue&#xff09;&#xff1a; 代码&#xff1a; 六、题目&#xff08;费里的语言 map&…

【Spring底层原理高级进阶】Spring Kafka:实时数据流处理,让业务风起云涌!️

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《Spring 狂野之旅&#xff1a;从入门到入魔》 &#x1f680; 本…

三星成功研发出业界首款12层堆叠HBM3E

三星电子有限公司成功研发出业界首款12层堆叠HBM3E DRAM——HBM3E 12H&#xff0c;这是迄今为止容量最大的HBM产品。这款新型HBM3E 12H内存模块提供了高达1,280GB/s的史上最高带宽&#xff0c;并拥有36GB的存储容量&#xff0c;相较于之前的8层堆叠HBM3 8H&#xff0c;在带宽和…