欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 手游 > 【C++】C++的引用

【C++】C++的引用

2025/4/21 6:38:28 来源:https://blog.csdn.net/qq_62917398/article/details/147192364  浏览:    关键词:【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的地址:0x7fff4d1e2090b的地址:0x7fff4d1e2090p的地址:0x7fff4d1e208cx的地址:0x7fff4d1e208cq的地址:0x7fff4d1e20eey的地址:0x7fff4d1e20eee的地址:0x7fff4d1e20d0z的地址:0x7fff4d1e20d0e的地址:0x7fff4d1e20d0o的地址:0x7fff4d1e20d0 
*/

2.1 指向普通变量的引用

示例代码:

#include <iostream>using namespace std; //使用命名空间stdint main(int argc, char const *argv[])
{int a = 666;
/* 有两种叫法: 1、定义引用叫做b,b指向a2、定义引用叫做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的地址:0x7fffc34d00dcb的地址:0x7fffc34d00dca的值:666b的值: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的地址: 0x7ffe22938920p存放的地址: 0x7ffe2293891cb2存放的地址: 0x7ffe2293891c*p存放的值: 45*b2存放的值: 45e[0] is: 45b4[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的地址:0x7ffcb1bd57d0fun1中stu.age的地址:0x7ffcb1bd57dcfun1中stu.score的地址:0x7ffcb1bd57e0fun1中stu.addr的地址:0x7ffcb1bd57e4引用成员地址fun2中stu.name的地址:0x7ffcb1bd5860fun2中stu.age的地址:0x7ffcb1bd586cfun2中stu.score的地址:0x7ffcb1bd5870fun2中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; //使用命名空间stdint 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; //使用命名空间stdint 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;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词