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++知识库 -> C++学习杂记(六)之引用 -> 正文阅读

[C++知识库]C++学习杂记(六)之引用


引用

  1. C/C++ 禁止在函数调用时直接传递数组的内容,而是强制传递数组指针。对于结构体和对象没有这种限制,调用函数时既可以传递指针,也可以直接传递内容。为了提高效率,建议传递指针。
  2. 传递聚合类型的数据(数组、结构体、类(对象)),除了上面说到的传递指针,在C++中还用到一种方式——引用。

一、引用的定义

  1. 引用可以看做是数据的一个别名,通过这个别名和原来的名字都能够找到这份数据。
  2. 语法格式
type &name = data;
//type 是被引用的数据的类型
//name 是引用的名称
//data 是被引用的数据。

注意:引用必须在定义的同时初始化,并且以后也要从一而终,不能再引用其它数据,这有点类似于常量(const 变量)。

#include <iostream>
using namespace std;
int main() {
    int a = 99;
    //用变量r引用变量a,注意,引用在定义时需要添加&,在使用时不能添加&。
    int &r = a;
    cout << a << ", " << r << endl; //99,99
    //发现变量r和变量a是同一个地址,所以通过引用也可以修改原始变量中所存储的数据。
    cout << &a << ", " << &r << endl; //0x28ff40,0x28ff40
    //改写引用变量,就改写原始变量的数据
    r =50;
    cout << a << "," << r << endl; //50,50
    return 0;
}

3.常引用
读者不希望通过引用来修改原始的数据,那么可以在定义时添加 const 限制。

const type &name = value; //const和type的顺序随意,也可以写成如下:
type const &name = value;

4.引用作为函数参数
在定义或声明函数时,我们可以将函数的形参指定为引用的形式,这样在调用函数时就会将实参和形参绑定在一起,让它们都指代同一份数据。
优点:在函数体中修改了形参的数据,那么实参的数据也会被修改,从而拥有“在函数内部影响函数外部数据”的效果。

#include<iostream>
using namespace std;

//函数声明
void swap1(int a, int b); //直接传递值参数
void swap2(int *p1, int *p2); //传递指针
void swap3(int &r1, int &r2); //传递引用

int main()
{
	int num1, num2;
	num1 = 11;
	num2 = 22;
	swap1(num1,num2);
	cout << num1 << "," << num2 << endl;

	num1 = 33;
	num2 = 44;
	swap2(&num1, &num2);
    cout << num1 << "," << num2 << endl;

	num1 = 55;
	num2 = 66;
	swap3(num1, num2);
    cout << num1 << "," << num2 << endl;

	cin.get();
	return 0;
}

void swap1(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}

void swap2(int *p1, int *p2) {
    int temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}

void swap3(int &r1, int &r2) {
    int temp = r1;
    r1 = r2;
    r2 = temp;
}

运行结果:
在这里插入图片描述
swap1是传值进行交换,其形参的作用域是局部的,所以swap1函数外的值未交换。
swap2是传递变量的指针,将地址传入,能够改写swap2函数外的num1和num2的值。
swap3是传入引用,能够达到函数内部修改形参,函数外的实参跟随改变。因为引用和实参代表同一份数据。

5.引用作为函数返回值
注意:引用作为返回值时,不能是局部变量,因为函数在调用后就销毁了,局部变量的数据就丢失了。(比如在plus10中定义一个int m作为返回值,那就是局部变量,这样会产生意想不到的结果)。

#include <iostream>
using namespace std;
int &plus10(int &r) {
    r += 10;
    return r;
}
int main() {
    int num1 = 5;
    int num2 = plus10(num1);
    cout << num1 << "," << num2 << endl; //15,15
	cin.get();
    return 0;
}

二、引用和指针的区别

1.引用只是对指针进行了简单的封装,它的底层依然是通过指针实现的,引用占用的内存和指针占用的内存长度一样,在 32 位环境下是 4 个字节,在 64 位环境下是 8 个字节,之所以不能获取引用的地址,是因为编译器进行了内部转换。
2.和指针的区别:
a. 引用必须在定义时初始化,并且以后也要从一而终,不能再指向其他数据;而指针没有这个限制,指针在定义时不必赋值,以后也能指向任意数据。
b. 可以有 const 指针,但是没有 const 引用。

int a = 20;
int & const r = a; //这种写法是不存在的,是错误的写法,原因引用在初始化后,它的指向就已经是不可以改变指向。

c. 指针可以有多级,但是引用只能有一级,例如,int **p是合法的,而int &&r是不合法的。
d. 指针使用 ++ 表示指向下一份数据,对引用使用 ++ 表示它所指代的数据本身加 1;自减也是同理。

#include <iostream>
using namespace std;
int main (){
    int a = 10;
    int &r = a;
    r++;
    cout<<r<<endl;//11
   
    int arr[2] = { 15, 23 };
    int *p = arr;
    p++;
    cout<<*p<<endl; //23
	cin.get();
    return 0;
}

三、C++引用不能绑定到临时数据

  1. 指针就是数据或代码在内存中的地址,指针变量指向的就是内存中的数据或代码。指针只能指向内存,不能指向寄存器或者硬盘,因为寄存器和硬盘没法寻址。
#include <iostream>
using namespace std;
int main (){
    int a = 10;
    int b = 15;
	//int *p = &(a+b); //这种写法直接报错,原因是a+b的和这个中间结果会被放在寄存器中,而指针需要指向内存
	//改成下面的写法即可
	int c;
	int*p =&c;
	c = a + b;
	cout<<*p<<endl;
	cin.get();
    return 0;
}
  1. 什么数据会放在寄存器中
    寄存器离 CPU 近,并且速度比内存快,将临时数据放到寄存器是为了加快程序运行。一般将较小的临时数据(int/double等基础类型)放在寄存器中,而结构体、对象等自定义的数据,大小不可测,通常放在内存中。

3.常量表达式是不能被寻址的。
原因是常量表达式是不包含变量的常量,在编译阶段编译器会将它直接放到虚拟地址空间中的代码区。类似汇编中的立即数,直接被编码到指令,不能寻址。

4.引用也不能指代临时数据。
原因是引用和指针在本质上是一样的,引用仅仅是对指针进行了简单的封装。引用和指针都不能绑定到无法寻址的临时数据。

5.当引用作为函数参数时,参数是引用类型,只能传递变量,不能传递常量或者表达式。

  1. 编译器会为const引用创建临时变量。
    引用一般不能绑定到临时数据,但是当使用const 关键字对引用加以限定后,引用就可以绑定到临时数据了。原因是编译器会为临时数据创建一个新的、无名的临时变量,并将临时数据放入该临时变量中,然后再将引用绑定到该临时变量。注意,临时变量也是变量,所有的变量都会被分配内存。
bool isOdd(const int &m)
{
    if(0 == m/2)
    {
       return false;
    }
    else
    {
       return true;
    }
}
int main()
{
   int a = 100;
   isOdd(a); //a作为普通变量,有内存,不会自动给它创建临时变量
   isOdd(a+9); //a+9是临时变量,犹豫引用是const,所以会自动创建临时变量。
   return 0;
}

7.编译器禁止指针指向不同类型的数据。引用同样也是这个道理。

#include <iostream>
using namespace std;
int main (){
    int n = 100;
    float *p = (float*)&n;
    *p = 20.263;
    printf("%d\n",n);  

	cout<<*p<<endl;
	cin.get();
    return 0;
}

运行结果:
在这里插入图片描述
原因是:对于 int,程序把最高 1 位作为符号位,把剩下的 31 位作为数值位;
对于 float,程序把最高 1 位作为符号位,把最低的 23 位作为尾数位,把中间的 8 位作为指数位。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-10 13:14:33  更:2021-08-10 13:15:24 
 
开发: 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/9 16:59:41-

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