1.什么是c++引用?
引用是c++对c的重要扩充。c++中新增了引用的概念,引用可以作为一个已定义变量的别名。
#include "stdafx.h"
#include <iostream>
using namespace std;
// 1.引用的基本使用
void test01(){
int a = 10;
// 给变量a取一个别名为b
int &b = a;
cout << "a:" << a << endl;
cout << "b:" << b << endl;
cout << "----------" << endl;
// 操作b就相当于操作a本身
b = 100;
cout << "a:" << a << endl;
cout << "b:" << b << endl;
cout << "----------" << endl;
// 一个变量可以有n个别名
int &c = a;
c = 200;
cout << "a:" << a << endl;
cout << "b:" << b << endl;
cout << "c:" << c << endl;
cout << "-----------" << endl;
// a,b,c的地址都是相同的
cout << "a:" << &a << endl;
cout << "b:" << &b << endl;
cout << "c:" << &c << endl;
}
// 2.使用引用注意事项
void test01(){
// (1)引用必须初始化
// int &ref; // 报错:必须初始化引用
// (2)引用一旦初始化,不能改变引用
int a = 10;
int b = 20;
int &ref = a;
// ref = b; // 不能改变引用
}
int main(){
test01();
return 0;
}
建立数组的引用
#include "stdafx.h"
#include <iostream>
using namespace std;
int main(){
// 1.建立数组引用方法一
typedef int ArrRef[10];
int arr[10];
ArrRef& aRef = arr; // 给数组arr取别名为ArrRef
for (int i = 0; i < 10;i++){
aRef[i] = i + 2;
}
for (int i = 0; i < 10;i++){
cout << arr[i] << " ";
}
cout << endl;
// ★2.建立数组引用方法二
int(&f)[10] = arr;
for (int i = 0; i < 10;i++){
f[i] = f[i] + 10;
}
for (int i = 0; i < 10;i++){
cout << arr[i] << " ";
}
cout << endl;
// ★ &arr == &aRef == &f
return 0;
}
2.引用的本质
引用的本质是在c++内部实现一个常指针。
Type& ref = val; // Type* const ref = &val;
c++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同,只是这个过程是编译器内部实现,用户不可见。
#include "stdafx.h"
#include <iostream>
using namespace std;
// 发现是引用,转换为 int* const ref = &a;
void testFunc(int& ref){
ref = 100; // ref是引用,转换为*ref = 100
}
int main(){
int a = 10;
int& aRef = a; //自动转换为int* const aRef = &a; 这也能说明引用为什么必须初始化
aRef = 20; // 内部发现aRef是引用,自动帮我们转换为:*Ref=20;
cout << "a:" << a << endl;
cout << "aRef:" << aRef << endl;
testFunc(a);
return 0;
}
3.指针的引用(重难点)
下面就是p1就是翠花的变量别名。cout<<p1得到结果就是翠花。
给指针变量取别名,就是指针的引用。我们可以把下面指针引用进行类比,就好理解了:
char* p = "翠花" // 等价于 int a = 10
char* &p1 = p // 等价于int &b=p
// 这就相当于引用的基本用法呗。
指针的引用,代码如下所示:
#include "stdafx.h"
#include <iostream>
using namespace std;
void test01(){
char* p = "翠花";
char* &p1 = p;
cout << p1 << endl;
}
int main(){
test01();
system("pause");
return 0;
}
一个字节对应的是8位,而malloc(size)中的size是以字节为单位。
#include <iostream>
using namespace std;
// 被调函数
void func(char* *tmp){
char *p;
p = (char*)malloc(64); // 64个字节大小
memset(p, 0, 64); // 清空p的内存,64个长度
strcpy(p, "小花"); // 拼接字符串
*tmp = p; // 一级指针*tmp装的是变量*p的地址p。
}
// 主调函数
void test01(){
char* mp = NULL;
func(&mp); // 二级指针装的是一级指针变量的地址。这个可以看【c一级指针二级指针那篇文章】
cout << mp << endl;
}
int main(){
test01();
system("pause");
return 0;
}
使用指针变量引用方法:
#include <iostream>
using namespace std;
// 被调函数
void func(char* &tmp){ // ★等价于 char* &tmp = mp,这叫给指针变量mp取别名为tmp。
char* p;
// 那p到底是变量值还是地址?变量值
p = (char*)malloc(64); // 64个字节大小
memset(p, 0, 64); // 清空p的内存,64个长度
strcpy(p, "小花你好"); // 拼接字符串
tmp = p; // 省略了*
}
// 主调函数
void test01(){
char* mp = NULL;
func(mp); // 省略了&
cout << mp << endl;
}
int main(){
test01();
system("pause");
return 0;
}
4.引用的使用场景
第一种:引用作为参数
#include <iostream>
using namespace std;
// 被调函数
void func(int &a, int &b){ // int &a=a相当于给变量a取别名为a。
int sum = a + b;
cout << "sum=" << sum << endl;
}
// 主调函数
void test01(){
int a = 10;
int b = 20;
func(a, b);
}
int main(){
test01();
system("pause");
return 0;
}
第二种:引用作为函数的返回值
#include <iostream>
using namespace std;
int &func2(){ // 声明这个函数的返回值是个引用,那么接收也要是引用变量。
int b = 10;
int &p = b;
return p;
}
void test01(){
int &q = func2();
cout << q << endl;
// 可以通过变名改变值
q = 100;
cout << q << endl;
// 也可以通过函数返回值改变值
func2() = 200;
cout << q << endl;
}
int main(){
test01();
system("pause");
return 0;
}
5.常量引用和普通引用区别
#include <iostream>
using namespace std;
int main(){
// 普通引用
int a = 10;
int &ref = a;
ref = 20;
// int &ret2 = 10; // 不能给字面量取别名 err
const int &ref3 = 10; // 可以给const修饰的引用赋予字面量
// const修饰符修饰的引用的原理
// 编译器会把上面的代码变为: int tmp = 10; const int &ref3 = tmp;
system("pause");
return 0;
}
6.函数的默认参数和占位参数
#include <iostream>
using namespace std;
int myFunc(int a, int b = 0){
return a + b;
}
void test01(){
// 函数的默认参数的作用
// 当函数内常要用到形参的某个值,但偶尔要使用其他值
// 增加函数的灵活性
cout << myFunc(10, 20) << endl;
cout << myFunc(10) << endl;
}
int main(){
test01();
system("pause");
return 0;
}
两个注意点:
//注意点:
//1. 形参b设置默认参数值,那么后面位置的形参c也需要设置默认参数
void TestFunc02(int a,int b = 10,int c = 10){}
//2. 如果函数声明和函数定义分开,函数声明设置了默认参数,函数定义不能再设置默认参数
void TestFunc03(int a = 0,int b = 0);
void TestFunc03(int a, int b){};
比如下面的例子是错误的:
#include <iostream>
using namespace std;
void TestFunc03(int a, int b= 0);
void TestFunc03(int a, int b = 1){ // 因为声明时候已经设置了默认参数b=0,了,那么定义时候就不能再设置默认参数b=1了。
cout << a + b << endl;
}
int main(){
TestFunc03(1, 2);
system("pause");
return 0;
}
7。函数传递参数的三种方式
#include <iostream>
using namespace std;
// 值传递
void swap1(int a, int b){
int temp = a;
a = b;
b = temp;
}
// 指针传递
void swap2(int *a, int *b){
int temp = *a;
*a = *b;
*b = temp;
}
// 引用传递
void swap3(int &a, int &b){
int temp = a;
a = b;
b = temp;
}
//打印
void myprint(int &a, int &b){
cout << "a=" << a <<" "<< "b=" << b << endl;
}
int main(){
int a = 10;
int b = 20;
cout << "初始值:" << a << " " << b<<endl;
swap1(a, b); // 注意点swap(a,b)是内部方法
myprint(a,b); // 10 , 20。因为形参的a和实参的a不是同一个
swap2(&a, &b); //
myprint(a, b); // 20 , 10。
swap3(a, b); //
myprint(a, b); // 又被转回来了:10 , 20。
system("pause");
return 0;
}
值传递:
指针传递:
引用传递(别名):