IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 2021-07-26 -> 正文阅读

[C++知识库]2021-07-26

C++学习笔记3

1.3引用

1.3.1

C语言中可以使用指针改变实参的值,在C++中可以使用引用更简洁。另外,参数是值传递,函数域中形参重新分配内存,而把实参的值传递到新分配的内存中,或者实参是一个复杂的对象,需要重新分配内存,使得效率降低。
引用声明如下:类型标识符 &引用名 = 目标变量名;
例如:

float a ;//声明一个浮点型变量
float &pa = a;.//声明pa是一个float型变量的引用,被初始化为a

类型与人的小名,外号例如:鲁迅和周树人是同一人。由于只是一个代号,所以pa本身并没有另辟内存,周树人就是鲁迅,陆逊就是周树人。有个别名并没有创造新的鲁迅。
注意:这里&是引用符号不是地址符号。
引用需要注意以下几点:
(1)声明一个引用的时候同时需要初始化,因为它是某一变量的别名。例如:没有鲁迅就没有周树人,在鲁迅这个新名字开始使用时,就意味着时鲁迅等同于周树人了。

int a=1 ,b=2;
int &t=a;//true (声明引用同时初始化,从今天起我“周树人”就叫鲁迅了。)
int &t;//errory

(2)当一个引用声明完毕后,相当于目标变量有两个名字引用名和原名字,在执行该函数时不可以其他变量在使用该引用名,鲁迅这个名字正在被周树人用,其他人此时再用会冲突。

int a=1 ,b=2;
int &t=a;
//int &t=b;//小绿和小红都叫小三,到底谁是小三?
int t = b;//这里t=2,相当于b的值给了a的内存空间,同时也被叫t。

(3)一个引用也可以有引用,相当于一个变量有两个引用,两个新的名字,

int a=1int &b=a;
int &c=a;//

(4)引用不能为空。

int a =3;
int &b=a;//ok;
int &c=NULL;//error,引用不能为空

观察下面的例子:

#include<iostream>
using namespace std;
int main()
{    
	
	int x,y=36;
	int &refx=x,&refy=y;
	refx = 12; 
	cout<<"x="<<x<<" "<<"refx="<<refx<<endl;
	cout<<"y="<<y<<" "<<"refy="<<refy<<endl;
	refx = y;  
	cout<<"x="<<x<<" "<<"refx="<<refx<<endl;
	cout<<"&x="<<&x<<" "<<"&refx="<<&refx<<endl;//地址运算符
	cout<<"&y="<<&y<<" "<<"&refy="<<&refy<<endl;
	return 0 ;
}
运行结果:
x=12 refx=12
y=36 refy=36
x=36 refx=36
&x=0019FF2C &refx=0019FF2C
&y=0019FF28 &refy=0019FF28
Press any key to continue

从上面结果可以看出,y只是赋值给refx,但是并没有改变原来的地址,refx仍然是和x绑定在一起,refx和x同一内存空间。

1.3.2 引用作为函数参数

引用在C++中主要有两个作用作为函数参数,和作为函数返回值。其中主要利用的是作为函数参数,传递数据的功能。
传统C语言中,函数在调用时,参数是通过值来传递的(实参赋值给形参),也就是说函数的参数不具备返回值的能力,是单向传递的,在函数运行时,实参与形参不占据同一个内存单元。
例子:实现两个变量的值互换。

#include<iostream>
using namespace std;
void swap(int a,int b)
{	
	int temp;
	temp =a;
	a=b;
	b=temp;
}


int main()
{    
	int n=1,m=2;
	cout<<n<<","<<m<<endl;
	swap(n,m);
	cout<<n<<","<<m<<endl;
	return 0;

}

运行结果
1,2
1,2
Press any key to continue

正如上面所述,实参赋值给形参变量,形参在函数运行时交换数值,结束时释放,除去赋值过程其他与实参无关。

	#include<iostream>
using namespace std;
void swap(int *a,int *b)
{	
	int temp;
	temp =*a;
	*a=*b;
	*b=temp;
}


int main()
{    
	int n=1,m=2;
	cout<<n<<","<<m<<endl;
	swap(&n,&m);
	cout<<n<<","<<m<<endl;
	return 0;

}
运行结果:	
1,2
2,1
Press any key to continue

如上面程序看到n,m变量的地址传递给了指针变量啊a,b。此时a,n为指向同一内存单元,m,b同理也是,当a,b交换了他们所指向的值意味着n,m交换了值,且函数结束时,只是变量a,b被释放,所以成功交换。这样做需要占用新的内存空间用指针运算符去兜一圈访问。使用引用就可以成功解决麻烦。
通过引用交换两个整数:

#include<iostream>
using namespace std;
void swap(int &a,int &b)
{	
	int temp;
	temp =a;
	a=b;
	b=temp;
}
int main()
{    
	int n=1,m=2;
	cout<<n<<","<<m<<endl;
	swap(n,m);
	cout<<n<<","<<m<<endl;
	return 0;

}
运行结果:
1,2
2,1
Press any key to continue

相当于int &a=n,&b=m; 此时n,m有了小名,利用别名交换数值,然后释放别名。这样看起来很简洁。
有了对以上引用的熟悉,所以进一步细节的讨论:

  1. 不能建立void类型的引用,如:
    void &a=9; //错误;
    因为任何变量都不是void类型的,void的含义是 无类型或者空类型,void只是在语法上相当于类型而已。
  2. 不能建立数组。如:
    char c[6]=“hello”;
    char&r[6]=c; //错误
    企图建立一个6个元素的引用的数组,数组名只代表数组的首地址。
  3. 可以将变量的引用地址赋值给一个指针,此时指针指向原变量。
    int a=3;//变量类型整形 int
    int &b=a;//变量类型int, 此时&为引用声明
    int *p=&b;//地址b被编译器认为是‘int *’
    下面这个是错误的:
    int &*p=&a; //此时编译器认为int &*为int * * ,在不是指针定义是认为p是int *在加上外面的,所以为int **,这里企图定义指向引用类型的指针变量p(int &)
    int *&p=&a;//error 编译器认为int *&和int *无法转换,我认为和上面类似错误int * *不能和 int *转化
    由于引用不是一种独立的数据类型,因此不能建立指向引用类型的指针变量。
    为了便于记忆这些奇怪的符号,左边在定义时英文字母都是新的变量,右边的是以前定义过的。奇怪的符号都是修饰符。
  4. 建立指针变量的引用
    int i =5; //
    int *p=&i; //
    int *&pt=p; //个人理解:整个一句话必然说明pt是某一个变量的引用,int * 说明pt是一个指向整形变量的指针变量类型(类型是pt变量的属性,&则是声明我是在引用)由于是指针变量类型所以右边是一个指针变量p,也就是再给p起一个名字但是类型必须得对应上。
  5. 可以用const限定,不允许改变变量的值。
    int i = 5;//定义整形变量i,初值为5
    const int &a=i;//声明常引用,不允许改变a的值
    a=3;//错误
    i=3;//true ,此时输出i和a的值都是3
    这个特性经常被用来保护形参不被改变

函数通常只返回一个值,通过引用相当于函数返回指定位置多个值。
例如:编写一个函数实现返回多个值。
方法一利用指针:

#include<iostream>
using namespace std;
void f(int,int*,int*);
int main()
{    
	int x1,x2,x3;
	x1=20;
	f(x1,&x2,&x3);
	cout<<x1<<" "<<x2<<" "<<x3<<endl;
	return 0;

}
void f(int n,int *n1 ,int *n2)
{
	*n1 = n+10;
	*n2 = n-10;
}

运行结果:
20 30 10
Press any key to continue

方法二利用引用:

#include<iostream>
using namespace std;
void f(int,int&,int&);
int main()
{    
	int x1,x2,x3;
	x1=20;
	f(x1,x2,x3);
	cout<<x1<<" "<<x2<<" "<<x3<<endl;
	return 0;

}
void f(int n,int &n1 ,int &n2)
{
	n1 = n+10;
	n2 = n-10;
}
运行结果:
20 30 10
Press any key to continue

若以引用作为函数返回值,则函数定义成以下格式:
类型标识符 &函数名(形参列表以及类型说明);
{函数主体}
例子:

#include<iostream>
using namespace std;
int f;
int f1(int a);
int &f2(int a);
int main()
{    
	int n =f1(2);
	int m =f2(5);
	cout<<n<<" "<<m<<endl;
	return 0;

}
int f1(int a)
{
	f =3*a;
	return f;
}
int &f2(int a)
{
	f = 3*a;
	return f;
}
运行结果:
6 15
Press any key to continue

f1和f2的不同在于返回值不产生临时变量,不占用系统内存。
f1返回6时通过局部变量传递给n,而f2相当于返回全局变量的引用.
以上有个人理解,有可能存在错误!!!!
┭┮﹏┭┮

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-01 14:19:22  更:2021-08-01 14:20:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/1 7:10:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码