当前位置: 首页 > news >正文

【C++】C++的引用

C++的引用

  • 1. 引用的概念
  • 2. 语法规则
    • 示例代码:三种常见引用的定义
    • 2.1 指向普通变量的引用
      • 示例代码:
    • 2.2 指向指针的引用
    • 2.3 指向数组的引用
    • 2.4 示例代码 引用的使用:
  • 3. 特点
    • 3.1 引用仅仅只是变量的一个别名,不占用额外的内存空间
      • 示例代码:
    • 3.2 引用具备了传值和传地址的双重属性
      • 示例代码:
    • 3.3 引用必须在定义的时候立马初始化(例外的情况:引用作为参数除外)
      • 示例代码:
    • 3.4 引用初始化以后不可以被改变
      • 示例代码:
    • 3.5 void fun(int &x) // 此时实参只能是左值,不能是右值
      • 示例代码:

1. 引用的概念

定义:变量的一个别名

  • C语言中传参的方式总共两种: 传值,传地址
  • C++中传参的方式总共三种: 传值,传地址,传引用

2. 语法规则

类型名  &引用的名字=变量名;

比如: 
    int  a=45;
    int  &b=a;  // 定义了一个引用b,b指向a
                // 定义了一个引用b,b是a的别名
    float a=56.5;
    float &b=a;
    struct student a={"张三",18};
    struct student &b=a;

示例代码:三种常见引用的定义

#include <iostream>

using namespace std; //使用命名空间std

//公式:类型名  &引用的名字 = 变量名;

int main(int argc, char const *argv[])
{
    //第一种:指向普通变量的引用
    double a = 45.6;
    double &b = a; // 定义引用
    cout<<"a的地址:"<<&a<<endl;
    cout<<"b的地址:"<<&b<<endl;
    //第二种:指向指针的引用
    int c = 45;
    int *p = &c;
    int *&x = p; // 定义引用
    cout<<"p的地址:"<<p<<endl;
    cout<<"x的地址:"<<x<<endl;

    char d[10] = "hello";
    char *q = d;
    char *&y = q; // 定义引用
    cout<<"q的地址:"<<(int *)q<<endl;
    cout<<"y的地址:"<<(int *)y<<endl;

    //第三种:指向数组的引用
    int e[5] = {45,96};
    // 第一种书写方式
    int  (&z)[5]= e;  // 定义引用
    cout<<"e的地址:"<<e<<endl;
    cout<<"z的地址:"<<z<<endl;

    // 第二种书写方式
    typedef int array[5];   // 给int [5] 取别名 为 array 
    array &o = e; // 定义引用
    cout<<"e的地址:"<<e<<endl;
    cout<<"o的地址:"<<o<<endl;

    return 0;
}

/* 
执行结果:
    a的地址:0x7fff4d1e2090
    b的地址:0x7fff4d1e2090
    p的地址:0x7fff4d1e208c
    x的地址:0x7fff4d1e208c
    q的地址:0x7fff4d1e20ee
    y的地址:0x7fff4d1e20ee
    e的地址:0x7fff4d1e20d0
    z的地址:0x7fff4d1e20d0
    e的地址:0x7fff4d1e20d0
    o的地址:0x7fff4d1e20d0 
*/

2.1 指向普通变量的引用

示例代码:

#include <iostream>

using namespace std; //使用命名空间std

int main(int argc, char const *argv[])
{
    int a = 666;
/* 
    有两种叫法: 
    1、定义引用叫做b,b指向a
    2、定义引用叫做b,b是a的别名
*/ 
    int &b = a; 

    // 证明引用就是变量的别名==》打印地址
    cout<<"a的地址:"<<&a<<endl;
    cout<<"b的地址:"<<&b<<endl;

    cout<<"a的值:"<<a<<endl;
    cout<<"b的值:"<<b<<endl;

    return 0;
}

/*
执行结果:
    a的地址:0x7fffc34d00dc
    b的地址:0x7fffc34d00dc
    a的值:666
    b的值:666
*/

2.2 指向指针的引用

int a=89; 
int *p=&a;
int *&b=p;  //定义了指向p的引用
char  buf[10]="hello";
char *q=buf;
char *&b=q;

2.3 指向数组的引用

int buf[10];      //类型  int[10]

// 第一种表达方式
typedef    int array[10];
array &b=buf;
// 第二种表达方式
int  (&b)[5]= buf;

2.4 示例代码 引用的使用:

总结:只要是引用,写代码的时候,当成指向的变量去使用即可

#include <iostream>

using namespace std; //使用命名空间std

//公式:类型名  &引用的名字 = 变量名;

int main(int argc, char const *argv[])
{
    //第一种:指向普通变量的引用
    double a = 45.6;
    double &b1 = a; // 定义引用
    // cout<<"a的地址:"<<&a<<endl;
    // cout<<"b的地址:"<<&b<<endl;
    //第二种:指向指针的引用
    int c = 45;
    int *p = &c;
    int *&b2 = p; // 定义引用
    // cout<<"p的地址:"<<p<<endl;
    // cout<<"x的地址:"<<x<<endl;

    char d[10] = "hello";
    char *q = d;
    char *&b3 = q; // 定义引用
    // cout<<"q的地址:"<<(int *)q<<endl;
    // cout<<"y的地址:"<<(int *)y<<endl;

    //第三种:指向数组的引用
    int e[5] = {45,96};
    // 第一种书写方式
    int  (&b4)[5]= e;  // 定义引用
    // cout<<"e的地址:"<<e<<endl;
    // cout<<"z的地址:"<<z<<endl;

    // 第二种书写方式
    typedef int array[5];   // 给int [5] 取别名 为 array 
    array &o = e; // 定义引用
    // cout<<"e的地址:"<<e<<endl;
    // cout<<"o的地址:"<<o<<endl;

    // 引用的使用:只要是引用(无论什么类型),写程序时,当成指向的变量去使用即可
    //a怎么用,b1就照着写
    cout<<"修改前a的值: "<<a<<endl;   
    cout<<"修改前b1的值: "<<b1<<endl;
    cout<<"修改前a的地址: "<<&a<<endl;
    cout<<"修改前b1的地址: "<<&b1<<endl;

    a=78.9;
    b1=28.9;
    cout<<"修改后a的值: "<<a<<endl;   
    cout<<"修改后b1的值: "<<b1<<endl;
    cout<<"修改后a的地址: "<<&a<<endl;
    cout<<"修改后b1的地址: "<<&b1<<endl;
    
    //p怎么用,b2就照着写
    cout<<"p存放的地址: "<<p<<endl;
    cout<<"b2存放的地址: "<<b2<<endl;
    
    cout<<"*p存放的值: "<<*p<<endl;
    cout<<"*b2存放的值: "<<*b2<<endl;
    
    //e怎么用,b4就照着写
    cout<<"e[0] is: "<<e[0]<<endl;
    cout<<"b4[0] is: "<<b4[0]<<endl;
    return 0;
}

/* 
执行结果:
    修改前a的值: 45.6
    修改前b1的值: 45.6
    修改前a的地址: 0x7ffe22938920
    修改前b1的地址: 0x7ffe22938920
    修改后a的值: 28.9
    修改后b1的值: 28.9
    修改后a的地址: 0x7ffe22938920
    修改后b1的地址: 0x7ffe22938920
    p存放的地址: 0x7ffe2293891c
    b2存放的地址: 0x7ffe2293891c
    *p存放的值: 45
    *b2存放的值: 45
    e[0] is: 45
    b4[0] is: 45
*/

3. 特点

3.1 引用仅仅只是变量的一个别名,不占用额外的内存空间

ps:引用本质上也是用指针来实现的,底层也分配了存储空间

应用:引用作为函数的形参,作为函数的返回值,使用频率最高(提高程序运行效率)

示例代码:

#include <iostream>

using namespace std; //使用命名空间std

/* 
    使用引用:为了提高程序的运行效率
*/ 
typedef struct student{
    char name[10];
    int age;
    float score;
    char addr[100];
}student_t;

void fun1(student_t stu)
{
    cout<<"传值成员地址"<<endl;
    cout<<"fun1中stu.name的地址:"<<(int *)(stu.name)<<endl; // cout中字符数组需要强转成int*才可打印地址,否则输出的是字符串
    cout<<"fun1中stu.age的地址:"<<&(stu.age)<<endl;
    cout<<"fun1中stu.score的地址:"<<&(stu.score)<<endl;
    cout<<"fun1中stu.addr的地址:"<<(int *)(stu.addr)<<endl; // cout中字符数组需要强转成int*才可打印地址,否则输出的是字符串
}

void fun2(student_t &stu)
{
    cout<<"引用成员地址"<<endl;
    cout<<"fun2中stu.name的地址:"<<(int *)(stu.name)<<endl; // cout中字符数组需要强转成int*才可打印地址,否则输出的是字符串
    cout<<"fun2中stu.age的地址:"<<&(stu.age)<<endl;
    cout<<"fun2中stu.score的地址:"<<&(stu.score)<<endl;
    cout<<"fun2中stu.addr的地址:"<<(int *)(stu.addr)<<endl; // cout中字符数组需要强转成int*才可打印地址,否则输出的是字符串
}

int main(int argc, char const *argv[])
{
    student_t stu = {"李1", 12, 99.9, "山卡拉"};
    cout<<"实参成员地址"<<endl;
    cout<<"实参中stu.name的地址:"<<(int *)(stu.name)<<endl; // cout中字符数组需要强转成int*才可打印地址,否则输出的是字符串
    cout<<"实参中stu.age的地址:"<<&(stu.age)<<endl;
    cout<<"实参中stu.score的地址:"<<&(stu.score)<<endl;
    cout<<"实参中stu.addr的地址:"<<(int *)(stu.addr)<<endl; // cout中字符数组需要强转成int*才可打印地址,否则输出的是字符串

    fun1(stu); // 传值
    fun2(stu); // 传引用

    return 0;
}

/*
执行结果:可以看出引用传参的地址与实参成员地址相同,减少栈空间的使用,提高程序运行效率
    实参成员地址
        实参中stu.name的地址:0x7ffcb1bd5860
        实参中stu.age的地址:0x7ffcb1bd586c
        实参中stu.score的地址:0x7ffcb1bd5870
        实参中stu.addr的地址:0x7ffcb1bd5874
    传值成员地址
        fun1中stu.name的地址:0x7ffcb1bd57d0
        fun1中stu.age的地址:0x7ffcb1bd57dc
        fun1中stu.score的地址:0x7ffcb1bd57e0
        fun1中stu.addr的地址:0x7ffcb1bd57e4
    引用成员地址
        fun2中stu.name的地址:0x7ffcb1bd5860
        fun2中stu.age的地址:0x7ffcb1bd586c
        fun2中stu.score的地址:0x7ffcb1bd5870
        fun2中stu.addr的地址:0x7ffcb1bd5874
*/

3.2 引用具备了传值和传地址的双重属性

即修改引用的形参相当于修改该地址的值

示例代码:

#include <iostream>

using namespace std; //使用命名空间std

/* 
    使用引用:为了提高程序的运行效率
*/ 
typedef struct student{
    char name[10];
    int age;
    float score;
    char addr[100];
}student_t;

void fun1(student_t stu)
{
    stu.age = 22;
    // cout<<"传值成员值"<<endl;
    // cout<<"fun1中stu.name的值:"<<(int *)(stu.name)<<endl; // cout中字符数组需要强转成int*才可打印地址,否则输出的是字符串
    // cout<<"fun1中stu.age的值:"<<&(stu.age)<<endl;
    // cout<<"fun1中stu.score的值:"<<&(stu.score)<<endl;
    // cout<<"fun1中stu.addr的值:"<<(int *)(stu.addr)<<endl; // cout中字符数组需要强转成int*才可打印地址,否则输出的是字符串
}

void fun2(student_t &stu)
{
    stu.age = 32;
    // cout<<"fun2中stu.name的值:"<<(int *)(stu.name)<<endl; // cout中字符数组需要强转成int*才可打印地址,否则输出的是字符串
    // cout<<"fun2中stu.age的地址:"<<&(stu.age)<<endl;
    // cout<<"fun2中stu.score的地址:"<<&(stu.score)<<endl;
    // cout<<"fun2中stu.addr的地址:"<<(int *)(stu.addr)<<endl; // cout中字符数组需要强转成int*才可打印地址,否则输出的是字符串
}

int main(int argc, char const *argv[])
{
    student_t stu = {"李1", 12, 99.9, "山卡拉"};

    cout<<"实参成员值(修改前)"<<endl;
    cout<<"实参中stu.name的值:"<<stu.name<<endl; // cout中字符数组需要强转成int*才可打印地址,否则输出的是字符串
    cout<<"实参中stu.age的值===========:"<<stu.age<<endl;
    cout<<"实参中stu.score的值:"<<stu.score<<endl;
    cout<<"实参中stu.addr的值:"<<stu.addr<<endl; // cout中字符数组需要强转成int*才可打印地址,否则输出的是字符串

    fun1(stu); // 传值
    cout<<"实参成员值(传值后)"<<endl;
    cout<<"实参中stu.name的值:"<<stu.name<<endl; // cout中字符数组需要强转成int*才可打印地址,否则输出的是字符串
    cout<<"实参中stu.age的值===========:"<<stu.age<<endl;
    cout<<"实参中stu.score的值:"<<stu.score<<endl;
    cout<<"实参中stu.addr的值:"<<stu.addr<<endl; // cout中字符数组需要强转成int*才可打印地址,否则输出的是字符串

    fun2(stu); // 传引用
    cout<<"实参成员值(传引用后)"<<endl;
    cout<<"实参中stu.name的值:"<<stu.name<<endl; // cout中字符数组需要强转成int*才可打印地址,否则输出的是字符串
    cout<<"实参中stu.age的值===========:"<<stu.age<<endl;
    cout<<"实参中stu.score的值:"<<stu.score<<endl;
    cout<<"实参中stu.addr的值:"<<stu.addr<<endl; // cout中字符数组需要强转成int*才可打印地址,否则输出的是字符串

    return 0;
}

/* 
执行结果:
    实参成员值(修改前)
    实参中stu.name的值:李1
    实参中stu.age的值===========:12
    实参中stu.score的值:99.9
    实参中stu.addr的值:山卡拉
    实参成员值(传值后)
    实参中stu.name的值:李1
    实参中stu.age的值===========:12
    实参中stu.score的值:99.9
    实参中stu.addr的值:山卡拉
    实参成员值(传引用后)
    实参中stu.name的值:李1
    实参中stu.age的值===========:32
    实参中stu.score的值:99.9
    实参中stu.addr的值:山卡拉 
*/

3.3 引用必须在定义的时候立马初始化(例外的情况:引用作为参数除外)

int a=78;
int &b;  
b=a;   //语法错误 
void swap3(int &a,int &b)  例外的情况:引用作为函数形参例外
{

}

示例代码:

#include <iostream>

using namespace std; //使用命名空间std

int main(int argc, char const *argv[])
{
    int a = 1;
    int &b;
    b = a;
    
    return 0;
}

编译时报错:
在这里插入图片描述

3.4 引用初始化以后不可以被改变

int a=78;
int b=98;
int &c=a;  //c是a的别名  
c=b;  //不要理解成引用c重新指向b,应该理解为把b的值赋值给了a(引用c是a的别名)

示例代码:

#include <iostream>

using namespace std; //使用命名空间std

int main(int argc, char const *argv[])
{
    int a = 1;
    int c = 2;
    //定义引用b,b是a的别名
    int &b = a;
    //b是a的别名,就永远都是a的别名
    //这个特点跟引用底层实现有关,因为引用的底层是用 int *const p;指针实现
    b = c;  // 等价于 a=c

    // 验证
    cout<<"a="<<b<<endl;

    return 0;
}

/* 
执行结果:
    a=2 
*/

3.5 void fun(int &x) // 此时实参只能是左值,不能是右值

fun(a);  // a是左值,正确
fun(88); // 88不是左值,错误   
fun(a+a); // a+a是右值,错误
void fun(const int &x) //此时实参可以是左值/右值

常应用:

const修饰的引用叫做常引用
常引用:
  作用1:防止引用修改指向的变量值
  作用2:实参传递的时候既能传递左值,也能传递右值
              int buf[8]={10,12};
              int otherbuf[8]
              buf=14;              //错误,数组名不能作为左值
              otherbuf=buf;    //错误,数组名不能作为左值
              buf=buf+1;        //错误,数组名不能作为左值
             int * const&b=buf;  //数组名只能作为右值,此时引用必须用const修饰才能指向右值
        
             int a=67;
             const int &c=a;  //等价于int const&c=a;
  作用3:如果是常量,定义引用,必须使用常引用
              const int a=78;
              const int &b=a;

示例代码:

#include <iostream>  //C++的标准输入输出流头文件 
using namespace std; //我要使用命名空间std
/*
    引用作为函数的形参:实参传递左值和右值
    概念:const修饰的引用叫做常引用
        例如: int a=45;
               const int &b=a;
    常引用的作用:
        作用1:函数的形参是常引用,实参可以传递左值也可以传递右值
               函数的形参是普通引用(非const修饰),实参只可以传递左值不能传递右值
        作用2:常引用不可以修改指向的变量值        
*/

//void fun(int &num)
void fun(const int &num)
{
    cout<<"num is: "<<num<<endl;
}
int main()  
{
    int n=456;
    //调用函数
    //写法1:
    fun(n);
    //写法2:
    /*
    error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’
    */
    fun(n+1);  //n+1是右值,普通引用不能传递右值
    //写法3:
    fun(147);    //147也是右值 ,普通引用不能传递右值
    
    
    return 0;
}

相关文章:

  • 在 Ubuntu 下通过 Docker 部署 Caddy 服务器
  • C++双链表介绍及实现
  • 从输入URL到页面渲染:浏览器请求的完整旅程解析
  • LLM学习笔记3——使用Docker(vLLM+OpenWebUI)实现本地部署DeepSeek-R1-32B模型
  • 基于HASM模型的高精度建模matlab仿真
  • Go 跨域中间件实现指南:优雅解决 CORS 问题
  • 十五、C++速通秘籍—异常处理
  • 基于Python的经济循环模型构建与可视化案例
  • Matlab添加标题title与标签lable
  • 上层 Makefile 控制下层 Makefile 的方法
  • 解释型语言和编译型语言的区别
  • 安全岗の夺命连环问:(第壹篇)从XSS到0day的灵魂拷问
  • 舵机、震动传感器、超声波使用代码
  • Qt 5.14.2 入门(四)菜单栏和工具栏的创建
  • 六、继承(三)
  • 如何用finallshell连接虚拟机
  • 前端下载文件时浏览器右上角没有保存弹窗及显示进度,下载完之后才会显示保存弹窗的问题定位及解决方案
  • PHP 拆词搜索(常用于搜索内容)
  • 从三次方程到复平面:复数概念的奇妙演进(一)
  • 多光谱相机:海洋管道漏油(溢油)监测
  • 青岛建设英文网站建设/网站免费优化软件
  • 安丘网站建设/深圳网站建设服务
  • 创业网站怎么做/seo推广哪家公司好
  • 做鸡婆的网站有没有/seo黑帽技术工具
  • 青岛艺腾网站建设/在线网页制作工具
  • 企业网站建设趋势/安徽网站seo公司