c++引用

news2024/11/24 17:50:11

1.什么是c++引用?

引用是c++对c的重要扩充。c++中新增了引用的概念,引用可以作为一个已定义变量的别名。

#include "stdafx.h"
#include <iostream>
using namespace std;
// 1.引用的基本使用
void test01(){
	int a = 10;
	// 给变量a取一个别名为b
	int &b = a;
	cout << "a:" << a << endl;
	cout << "b:" << b << endl;
	cout << "----------" << endl;
	// 操作b就相当于操作a本身
	b = 100;
	cout << "a:" << a << endl;
	cout << "b:" << b << endl;
	cout << "----------" << endl;
	// 一个变量可以有n个别名
	int &c = a;
	c = 200;
	cout << "a:" << a << endl;
	cout << "b:" << b << endl;
	cout << "c:" << c << endl;
	cout << "-----------" << endl;
	// a,b,c的地址都是相同的
	cout << "a:" << &a << endl;
	cout << "b:" << &b << endl;
	cout << "c:" << &c << endl;
}
// 2.使用引用注意事项
void test01(){
	// (1)引用必须初始化
	// int &ref; // 报错:必须初始化引用
	// (2)引用一旦初始化,不能改变引用
	int a = 10;
	int b = 20;
	int &ref = a;
	// ref = b; // 不能改变引用
}
int main(){
	test01();
	return 0;
}

建立数组的引用

#include "stdafx.h"
#include <iostream>
using namespace std;

int main(){
	// 1.建立数组引用方法一
	typedef int ArrRef[10];
	int arr[10];
	ArrRef& aRef = arr; // 给数组arr取别名为ArrRef
	for (int i = 0; i < 10;i++){
		aRef[i] = i + 2;
	}
	for (int i = 0; i < 10;i++){
		cout << arr[i] << " ";
	}
	cout << endl;
	// ★2.建立数组引用方法二
	int(&f)[10] = arr;
	for (int i = 0; i < 10;i++){
		f[i] = f[i] + 10;
	}
	for (int i = 0; i < 10;i++){
		cout << arr[i] << " ";
	}
	cout << endl;
	// ★ &arr == &aRef == &f
 	return 0;
}

2.引用的本质

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

Type& ref = val; // Type* const ref = &val;

c++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同,只是这个过程是编译器内部实现,用户不可见。

#include "stdafx.h"
#include <iostream>
using namespace std;

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

int main(){
	int a = 10;
	int& aRef = a; //自动转换为int* const aRef = &a; 这也能说明引用为什么必须初始化
	aRef = 20; // 内部发现aRef是引用,自动帮我们转换为:*Ref=20;
	cout << "a:" << a << endl;
	cout << "aRef:" << aRef << endl;
	testFunc(a);
 	return 0;
}

3.指针的引用(重难点)

下面就是p1就是翠花的变量别名。cout<<p1得到结果就是翠花。

给指针变量取别名,就是指针的引用。我们可以把下面指针引用进行类比,就好理解了:

char* p = "翠花" // 等价于 int a = 10
char* &p1 = p // 等价于int &b=p

// 这就相当于引用的基本用法呗。

指针的引用,代码如下所示:

#include "stdafx.h"
#include <iostream>
using namespace std;

void test01(){
	char* p = "翠花";
	char* &p1 = p;
	cout << p1 << endl;
}

int main(){
	test01();
	system("pause");
 	return 0;
}

一个字节对应的是8位,而malloc(size)中的size是以字节为单位。

#include <iostream>
using namespace std;

// 被调函数
void func(char* *tmp){
	char *p;
	p = (char*)malloc(64); // 64个字节大小
	memset(p, 0, 64); // 清空p的内存,64个长度
	strcpy(p, "小花"); // 拼接字符串
	*tmp = p; // 一级指针*tmp装的是变量*p的地址p。
}

// 主调函数
void test01(){
	char* mp = NULL;
	func(&mp); // 二级指针装的是一级指针变量的地址。这个可以看【c一级指针二级指针那篇文章】
	cout << mp << endl;
}

int main(){
	test01();
	system("pause");
	return 0;
}

使用指针变量引用方法:

#include <iostream>
using namespace std;

// 被调函数
void func(char* &tmp){ // ★等价于 char* &tmp = mp,这叫给指针变量mp取别名为tmp。
	char* p;
	// 那p到底是变量值还是地址?变量值
	p = (char*)malloc(64); // 64个字节大小
	memset(p, 0, 64); // 清空p的内存,64个长度
	strcpy(p, "小花你好"); // 拼接字符串
	tmp = p; // 省略了*
}

// 主调函数
void test01(){
	char* mp = NULL;
	func(mp); // 省略了&
	cout << mp << endl;
}

int main(){
	test01();
	system("pause");
	return 0;
}

4.引用的使用场景

第一种:引用作为参数

#include <iostream>
using namespace std;

// 被调函数
void func(int &a, int &b){ // int &a=a相当于给变量a取别名为a。
	int sum = a + b;
	cout << "sum=" << sum << endl;
}

// 主调函数
void test01(){
	int a = 10;
	int b = 20;
	func(a, b);
}

int main(){
	test01();
	system("pause");
	return 0;
}

第二种:引用作为函数的返回值

#include <iostream>
using namespace std;

int &func2(){ // 声明这个函数的返回值是个引用,那么接收也要是引用变量。
	int b = 10;
	int &p = b;
	return p;
}

void test01(){
	int &q = func2();
	cout << q << endl;
	//  可以通过变名改变值
	q = 100;
	cout << q << endl;
	// 也可以通过函数返回值改变值
	func2() = 200;
	cout << q << endl;
}

int main(){
	test01();
	system("pause");
	return 0;
}

5.常量引用和普通引用区别

#include <iostream>
using namespace std;

int main(){
	// 普通引用
	int a = 10;
	int &ref = a;
	ref = 20;
	
	// int &ret2 = 10; // 不能给字面量取别名 err
	const int &ref3 = 10; // 可以给const修饰的引用赋予字面量
	// const修饰符修饰的引用的原理
	// 编译器会把上面的代码变为: int tmp = 10; const int &ref3 = tmp;
	system("pause");
	return 0;
}

6.函数的默认参数和占位参数

#include <iostream>
using namespace std;

int myFunc(int a, int b = 0){
	return a + b;
}

void test01(){
	// 函数的默认参数的作用
	// 当函数内常要用到形参的某个值,但偶尔要使用其他值
	// 增加函数的灵活性
	cout << myFunc(10, 20) << endl;
	cout << myFunc(10) << endl;
}

int main(){
	test01();
	system("pause");
	return 0;
}

两个注意点:

//注意点:
//1. 形参b设置默认参数值,那么后面位置的形参c也需要设置默认参数
void TestFunc02(int a,int b = 10,int c = 10){}
//2. 如果函数声明和函数定义分开,函数声明设置了默认参数,函数定义不能再设置默认参数
void TestFunc03(int a = 0,int b = 0);
void TestFunc03(int a, int b){};

比如下面的例子是错误的:

#include <iostream>
using namespace std;

void TestFunc03(int a, int b= 0);
void TestFunc03(int a, int b = 1){ // 因为声明时候已经设置了默认参数b=0,了,那么定义时候就不能再设置默认参数b=1了。
	cout << a + b << endl;
}

int main(){
	TestFunc03(1, 2);
	system("pause");
	return 0;
}

7。函数传递参数的三种方式

#include <iostream>
using namespace std;

// 值传递
void swap1(int a, int b){
	int temp = a;
	a = b;
	b = temp;
}

// 指针传递
void swap2(int *a, int *b){
	int temp = *a;
	*a = *b;
	*b = temp;
}

// 引用传递
void swap3(int &a, int &b){
	int temp = a;
	a = b;
	b = temp;
}

//打印
void myprint(int &a, int &b){
	cout << "a=" << a <<" "<< "b=" << b << endl;
}

int main(){
	int a = 10;
	int b = 20;
	cout << "初始值:" << a << " " << b<<endl;
	swap1(a, b); // 注意点swap(a,b)是内部方法
	myprint(a,b); // 10 , 20。因为形参的a和实参的a不是同一个
	swap2(&a, &b); // 
	myprint(a, b); // 20 , 10。
	swap3(a, b); // 
	myprint(a, b); // 又被转回来了:10 , 20。
	system("pause");
	return 0;
}

值传递:

指针传递:

引用传递(别名):

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

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

相关文章

金仓数据库KingbaseES 归档日志清理

WAL是Write Ahead Log的简写&#xff0c;和Oracle的redo日志类似&#xff0c;在R3版本存放在data/sys_log中&#xff0c;R6版本以后在data/sys_wal目录&#xff0c;在数据库访问过程中&#xff0c;任何对数据块的修改都会记录到wal日志&#xff0c;并写入到wal文件保存到磁盘&a…

PMP有没有必要续证呢?

在还只看到标题的时候&#xff0c;我当时就觉得必须续啊&#xff0c;为什么不续&#xff0c;我花了那么多时间精力和钱财去考的&#xff0c;我自然得去给它续上&#xff0c;不然白拿了&#xff0c;才拿了三年我还没捂热就给我失效了多不值。 首先美国PMI要求PMP证书是三年一换…

面试题 :Unity编辑器基础

1、请描述游戏动画有几种&#xff0c;以及其原理。 关键帧动画&#xff1a;每一帧动画序列当中包含了顶点的空间位置信息以及改变量&#xff0c;然后通过插值运算&#xff0c;得出动画效果。选中某一游戏对象&#xff0c;创建animation&#xff0c;添加属性Transform&#xff0…

【Meetup 预告】OpenMLDB + MaxCompute:集成打通云上生态,高效构建 AI 应用

2022年12月3日&#xff08;周六&#xff09;上午10&#xff1a;00-12:00&#xff0c;开源机器学习数据库 OpenMLDB 第八期 Meetup 将通过线上直播的形式展开。 活动背景 数据的爆发式增长为 AI 应用的繁荣提供了坚实的基础&#xff0c;而云服务作为新一代快速整合、高效计算的…

STC-Seg:首个超越PointTrack的弱监督视频MOTS算法

弱监督视频多目标实例分割新SOTA&#xff08;代码已开源&#xff09;&#xff1a; Paper: Solve the Puzzle of Instance Segmentation in Videos: A Weakly Supervised Framework with Spatio-Temporal Collaboration Code: https://github.com/ylqi/STC-Seg 众所周知&#xf…

linux之syslog使用说明

syslog 系统日志应用 1) 概述 syslog默认的日志守护进程。默认的syslog配置文件是/etc/syslog.conf文件。程序&#xff0c;守护进程和内核提供了访问系统的日志信息。因此&#xff0c;任何希望生成日志信息的程序都可以向 syslog 接口呼叫生成该信息。 几乎所有的网络设…

【2台真机实战--Redis一主一从两哨兵配置集群和主从切换】

2台真机实战--Redis一主一从两哨兵配置集群和主从切换前言实战真实环境节点分布配置主服务器&#xff08;192.168.137.23&#xff09;配置redis.conf配置sentinel.conf从服务器&#xff08;192.168.137.24&#xff09;配置redis.conf配置sentinel.conf启动redis整合SpringBoot配…

[附源码]Node.js计算机毕业设计服装销售商城系统Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

python之路 socket、socket server

一、socket socket的英文原义是“孔”或“插座”。作为BSD UNIX的进程通信机制&#xff0c;取后一种意思。通常也 称作"套接字"&#xff0c;用于描述IP地址和端口&#xff0c;是一个通信链的句柄&#xff0c;可以用来实现不同虚拟机或不同计算机之间的通信。在Inter…

nodejs+vue大学生企业推荐系统vue

1、 node_modules文件夹(有npn install产生) 这文件夹就是在创建完项目后&#xff0c;cd到项目目录执行npm install后生成的文件夹&#xff0c;下载了项目需要的依赖项。 2、package.json文件 此文件是项目的配置文件&#xff08;可定义应用程序名&#xff0c;版本&am…

Java基础之并发理论基础

Java基础之并发理论基础一、为什么需要多线程二、线程不安全1、三要素之一可见性&#xff08;CPU缓存引起&#xff09;2、三要素之一原子性&#xff08;分时复用引起&#xff09;3、三要素之一有序性&#xff08;重排序引起&#xff09;一、为什么需要多线程 CPU 增加了缓存&a…

springcloud3 EurekaServer集群的搭建1

一 EurekaServer集群搭建 1.1 逻辑流程 服务的注册与发现 服务注册&#xff1a;向注册中心进行注册登记。 服务发现&#xff1a;从注册中心中获取服务器信息。 整个流程 1.首先eurekaServer先进行启动&#xff0c; 2.服务提供者开始启动并将自己的信息注册到EurekaServer上(前…

如何获取java加载器和类完整结构的方法?

类加载器的作用与类缓存&#xff1a; 类加载器的作用&#xff1a;将class文件字节码内容加载到内存中&#xff0c;并将这些静态数据转换成方法区的运行时数据结构&#xff0c;然后在堆中生成一个代表这个类的java.lang.Class对象&#xff0c;作为方法区中类数据的访问入口。 …

红绿灯(交通信号灯)检测数据集

深度学习目标检测&#xff1a;红绿灯(交通信号灯)检测数据集 目录 深度学习目标检测&#xff1a;红绿灯(交通信号灯)检测数据集 1.红绿灯数据集说明 &#xff08;1&#xff09;Traffic-Lights-Dataset-Domestic &#xff08;2&#xff09;Traffic-Lights-Dataset-Foreign …

第12部分 交换机基本配置

目录 12.1 交换机简介 12.2 实验1&#xff1a;交换机基本配置 1.实验目的 2.实验拓扑 3.实验步骤 12.3 实验2&#xff1a;交换机端口安全 1.实验目的 2.实验拓扑 3.实验步骤 4.实验调试 12.4 实验3&#xff1a;交换机的密码恢复 1.实验目的 2.实验拓扑 3.实验步骤…

React学习8(新旧生命周期)

组件的生命周期&#xff08;旧&#xff09; react生命周期&#xff08;旧&#xff09; 1.初始化阶段&#xff1a;由ReactDOM.render()触发---初次渲染 1.constructor(){} 2.componentWillMount() {} 3.render() {} 4.componentDidMount() {}----常用&#xff0c;一般在这个钩子…

ElasticSearch的数据存储及写入原理

数据存储 数据存储介绍 Elasticsearch 是面向文档型数据库&#xff0c;一条数据在这里就是一个文档。 为了方便大家理解&#xff0c;我们将 Elasticsearch 里存储文档数据和关系型数据库 MySQL 存储数据的概念进行一个类比。 注意&#xff1a;Types 的概念已经被逐渐弱化&…

上海亚商投顾:沪指全天窄幅震荡 大消费板块再掀涨停潮

上海亚商投顾前言&#xff1a;无惧大盘大跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪沪指全天窄幅震荡&#xff0c;创业板指高开低走。医药股大幅分化&#xff0c;新华制药6连板&#xff0c;股价创出历…

软件测试丨单元测试框架怎么搭?新版的Junit5有哪些神奇之处?

单元测试&#xff08;unit testing&#xff09;&#xff0c;是指对软件中的最小可测试单元进行检查和验证。 总的来说&#xff0c;单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动&#xff0c;软件的独立单元将在与程序的其他部…

12306接口采集

铁路客户服务中心https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date2022-12-22&leftTicketDTO.from_stationCQW&leftTicketDTO.to_stationETW&purpose_codesADULT请求头 Accept: */* Accept-Language: zh-CN,zh;q0.9 Cache-Control: no-cach…