目录
- 前言
- 011引用初探_引用与普通变量
- 012引用初探_引用作为函数参数
- 013引用初探_引用作为函数返回值
- 014引用初探_引用返回局部函数造成的错误
- 015引用初探_多级引用
- 020引用与指针递增的区别
- 030const与引用
- 040使用const限定的函数形参引用
前言
本笔记所涉及到的编程环境与 《C++ · 代码笔记1 · 从C到C++》 中的编程环境一致,具体可参考此笔记。
011引用初探_引用与普通变量
相关代码:
#include <iostream>
int main()
{
int a = 99; // 定义整型变量a并初始化为99
int &r = a; // 定义整型引用r并初始化为a的引用
std::cout << a << ", " << r << std::endl; // 输出a的值和r的值,由于r是a的引用,所以它们的值相同
std::cout << &a << std::endl; // 输出a的地址
std::cout << &r << std::endl; // 输出r的地址,由于r是a的引用,所以它们的地址也相同
return 0;
}
运行结果:
012引用初探_引用作为函数参数
相关代码:
#include <iostream>
/**
* 函数swap1:值传递方式交换两个整数
* @param a 第一个整数
* @param b 第二个整数
* 注意:此函数不会改变实参的值,因为它是通过值传递的
*/
void swap1(int a, int b)
{
int temp = a; // 使用临时变量保存a的值
a = b; // 将a的值设置为b
b = temp; // 将b的值设置为a原始的值
}
/**
* 函数swap2:指针传递方式交换两个整数
* @param p1 指向第一个整数的指针
* @param p2 指向第二个整数的指针
* 注意:此函数会改变实参的值,因为它是通过指针传递的
*/
void swap2(int *p1, int *p2)
{
int temp = *p1; // 使用临时变量保存p1指向的值
*p1 = *p2; // 将p1指向的值设置为p2指向的值
*p2 = temp; // 将p2指向的值设置为p1原始的值
}
/**
* 函数swap3:引用传递方式交换两个整数
* @param r1 第一个整数的引用
* @param r2 第二个整数的引用
* 注意:此函数会改变实参的值,因为它是通过引用传递的
*/
void swap3(int &r1, int &r2)
{
int temp = r1; // 使用临时变量保存r1的值
r1 = r2; // 将r1的值设置为r2
r2 = temp; // 将r2的值设置为r1原始的值
}
int main()
{
int num1, num2;
std::cout << "值传递,请输入两个整型数据: ";
std::cin >> num1 >> num2;
swap1(num1, num2);
std::cout << num1 << " " << num2 << std::endl;
std::cout << "指针传递,请输入两个整型数据: ";
std::cin >> num1 >> num2;
swap2(&num1, &num2);
std::cout << num1 << " " << num2 << std::endl;
std::cout << "引用传递,请输入两个整型数据: ";
std::cin >> num1 >> num2;
swap3(num1, num2);
std::cout << num1 << " " << num2 << std::endl;
return 0;
}
运行结果:
013引用初探_引用作为函数返回值
相关代码:
#include <iostream>
using namespace std;
/**
* 函数func:通过引用修改参数并返回引用
* @param r 输入的整型引用参数
* @return 返回修改后的整型引用
* 注意:此函数通过引用修改传入的参数,并且返回修改后的引用
*/
int &func(int &r)
{
r += 10; // 将传入的引用参数的值增加10
return r; // 返回修改后的引用参数
}
int main()
{
int num1 = 10; // 定义并初始化整型变量num1为10
int num2 = func(num1); // 调用func函数,传入num1的引用,并将返回的引用赋值给num2
// 此时num1和num2的值都为20,因为它们引用的是同一个变量
cout << num1 << " " << num2 << endl; // 输出num1和num2的值
return 0;
}
运行结果:
014引用初探_引用返回局部函数造成的错误
相关代码:
#include <iostream>
using namespace std;
/**
* 函数plus10:计算输入整型引用参数加10的结果,并返回一个新的整型引用
* @param r 输入的整型引用参数
* @return 返回一个新的整型引用,其值为输入参数加10
* 注意:此函数返回的是一个局部变量的引用,这是一个危险的操作,
* 因为局部变量在函数调用结束后会被销毁,返回其引用可能会导致未定义行为。
*/
int &plus10(int &r)
{
int m = r + 10; // 创建一个局部变量m,其值为输入参数r加10
return m; // 返回局部变量m的引用
}
int main()
{
int num1 = 10; // 定义并初始化整型变量num1为10
int num2 = plus10(num1); // 调用plus10函数,返回的是一个局部变量的值,此处是安全的
cout << num2 << endl; // 输出num2的值,即20
int &num3 = plus10(num1); // 调用plus10函数,返回局部变量的引用并赋值给num3
// 这里是危险的,因为num3现在引用了一个已经销毁的局部变量
int &num4 = plus10(num3); // 再次调用plus10函数,返回局部变量的引用并赋值给num4
// 这里同样是危险的,因为num4现在引用了一个已经销毁的局部变量
cout << num3 << " " << num4 << endl; // 输出num3和num4的值,这是未定义行为
return 0; // 程序结束,返回0
}
运行结果:
简单解释:事实上在编译的时候编译器已经发出了警告,其内容为返回了一个局部变量的引用。这是一个错误,因为局部变量在函数返回后就会销毁,返回的引用将指向一个不再有效的内存位置。
在运行的时候直接出现“段错误”,从此可以看出,绝对不要使用引用去返回一个局部变量,否则将会出现程序崩溃的后果。
015引用初探_多级引用
相关代码:
#include <iostream>
int main(int argc, char const *argv[])
{
int a = 10; // 定义整型变量a并初始化为10
int &r = a; // 定义整型引用r,并初始化为a的引用
int &rr = r; // 定义整型引用rr,并初始化为r的引用,即rr也是a的引用
// 输出rr、r和a的值,由于rr和r都是a的引用,它们的值与a相同
std::cout << "rr = " << rr << "\nr = " << r << "\na = " << a << std::endl;
return 0;
}
运行结果:
020引用与指针递增的区别
相关代码:
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
int a = 10; // 定义整型变量a并初始化为10
int &r = a; // 定义整型引用r,并初始化为a的引用
r++; // 通过引用r增加a的值
std::cout << r << std::endl; // 输出r的值,即a的值,现在是11
int arr[2] = {27, 84}; // 定义并初始化一个整型数组arr,包含两个元素27和84
int *p = arr; // 定义一个整型指针p,并初始化为指向数组arr的首地址
p++; // 将指针p向后移动一个位置,指向数组arr的第二个元素
std::cout << *p << std::endl; // 输出指针p所指向的值,即数组arr的第二个元素,值为84
return 0;
}
运行结果:
030const与引用
相关代码:
#include <iostream>
/* 引用不能绑定到临时数据,但是当使用 const 关键字对引用加以限定后,引用就可以绑定到临时数据了。 */
// 定义一个结构体S,包含两个整型成员a和b
typedef struct
{
int a; // 成员a
int b; // 成员b
} S;
// 函数func_int,返回一个整型值100
int func_int()
{
int n = 100; // 初始化整型变量n为100
return n; // 返回n的值
}
// 函数func_s,返回一个结构体S的实例,其成员a和b分别被赋值为100和200
S func_s()
{
S a; // 定义结构体变量a
a.a = 100; // 设置a的成员a为100
a.b = 200; // 设置a的成员b为200
return a; // 返回结构体变量a
}
// 重载+运算符,用于两个结构体S的实例相加
S operator+(const S &A, const S &B)
{
S C; // 定义结构体变量C,用于存储A和B相加的结果
C.a = A.a + B.a; // 设置C的成员a为A和B的成员a之和
C.b = A.b + B.b; // 设置C的成员b为A和B的成员b之和
return C; // 返回结构体变量C
}
// 程序的入口点
int main()
{
int m = 100, n = 36; // 定义并初始化整型变量m为100,n为36
// 以下都是通过字面量或表达式初始化的常量引用,注意它们都没有实际的对象与之绑定
const int &r1 = m + n; // 常量引用r1绑定到m和n的和上
const int &r2 = m + 28; // 常量引用r2绑定到m和28的和上
const int &r3 = 12 * 3; // 常量引用r3绑定到12和3的乘积上
const int &r4 = 50; // 常量引用r4绑定到字面量50上
const int &r5 = func_int(); // 常量引用r5绑定到函数func_int的返回值上
S s1 = {23, 45}; // 定义并初始化结构体变量s1的成员a为23,b为45
S s2 = {90, 75}; // 定义并初始化结构体变量s2的成员a为90,b为75
const S &r6 = func_s(); // 常量引用r6绑定到函数func_s的返回值上
const S &r7 = s1 + s2; // 常量引用r7绑定到s1和s2的和上
return 0; // 程序结束
}
运行结果:
040使用const限定的函数形参引用
相关代码:
#include <cstdio>
// 计算长方体的表面积
// @param len 长方体的长度
// @param width 长方体的宽度
// @param hei 长方体的高度
// @return 返回长方体的表面积
/* 使用 const 能让函数接收 const 和非 const 类型的实参,否则将只能接收非 const 类型的实参; */
double volume(const double &len, const double &width, const double &hei)
{
return len * width * 2 + len * hei * 2 + width * hei * 2;
}
// 程序的入口点
int main()
{
int a = 12, b = 3, c = 20; // 定义并初始化整型变量a为12,b为3,c为20
double v1 = volume(a, b, c); // 调用volume函数计算长方体的表面积,并存储结果到v1
double v2 = volume(10, 20, 30); // 调用volume函数计算长方体的表面积,并存储结果到v2
double v3 = volume(89.4, 32.7, 19); // 调用volume函数计算长方体的表面积,并存储结果到v3
double v4 = volume(a + 12.5, b + 23.4, 16.78); // 调用volume函数计算长方体的表面积,并存储结果到v4
double v5 = volume(a + b, a + c, b + c); // 调用volume函数计算长方体的表面积,并存储结果到v5
printf("%lf, %lf, %lf, %lf, %lf\n", v1, v2, v3, v4, v5); // 打印出v1, v2, v3, v4, v5的值
return 0;
}
运行结果: