一.引用
1.变量名
1.1变量名实质上是一段连续存储的空间的别名,类似于门牌号,程序中通过变量来申请并命名内存空间
1.2通过变量名来使用存储空间,那一段连续的内存空间是否可以有一个别名?
2.c++引用概念
引用可以看作一个已定义的变量的别名,语法:type &name = var
#include <stdio.h>
int main()
{
// 定义一个int型变量a,在内存中占4个字节,
// 变量名 a 就代表了这一块内存,或者说 a 是这块内存的别名
int a = 10;
// 定义了一个引用变量 b ,它是 a 的别名,和 a 代表同一块内存空间
// 对 b 的操作 和 对 a 的操作是一样的
int& b = a;
// 改变 b 等于改变了 a
b = 20;
printf ("%d, %d\n", a, b);
// a 与 b 代表同一块内存空间
printf ("%p, %p\n", &a, &b);
return 0;
}
注:普通引用在定义时必须用其他变量进行初始化,引用是一块空间的别名,若空间不存在,引用就没有意义
3.引用作为其它变量的别名而存在,因此在一些场合可以代替指针
#include <stdio.h>
void swap1 (int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
}
void swap2 (int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
int main()
{
int a = 10;
int b = 20;
swap2 (&a, &b);
swap1 (a, b);
printf ("%d, %d\n", a, b);
return 0;
}
4.复杂数据类型的传递
#include <stdio.h>
struct Student
{
char name[20];
int age;
};
void printS1(Student *pS)
{
printf ("%s , %d\n", pS->name, pS->age);
}
// 复杂数据类型的引用
void printS2(Student &pS)
{
printf ("%s\n", pS.name);
pS.age = 80;
}
void printS3(Student pS)
{
printf ("%s , %d\n", pS.name,pS->age);
}
int main()
{
Student stu = {"xiaoming", 2};
printS1(&stu); // 地址传递,pS 是 变量 stu 的指针,引用成员要用 ->
printS2(stu); // pS 是 stu 的别名,和 stu 代表的是同一块内存空间,使用成员和 stu 一样 用.
printf ("%d\n", stu.age);
printS3(stu); // 值传递,pS 是 stu 的一份复制
return 0;
}
5.引用类型是否占内存空间?
struct stu2
{
char &a;
char &b;
};
int main()
{
//C++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同
printf("%d\n",sizeof(stu2)); // 8
return 0;
}
引用的本质:
引用在C++内部实现是一个常指针,type &name ==> type *const name
C++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同,从使用的角度,引用会让人误会其只是一个别名,没有自己的存储空间。
#include <stdio.h>
int main()
{
int a = 10;
int &b = a; // int * const b = &a;
// *b = 20;
b = 20;
// printf ("%p, %p\n", &a, &(*b));
printf ("%p, %p\n", &a, &b);
return 0;
}
void func(int &a)
{
a = 20;
}
在编译器内部被转化为什么形式?
void func(int *const a)
{
*a = 20;
}
6.函数返回值作为引用,定义函数时在函数名前加 &
#include <stdio.h>
#include <iostream>
using namespace std;
//函数返回值作引用,定义函数时在函数名前加&
int &fun8()
{
static int a = 1;
a++;
printf("a = %d\n",a);
return a;
}
int main7_1()
{
//函数返回值时引用,用引用接,接回来的是一个引用
int &b = fun8(); //用引用接函数返回的引用 a = 2
b = 100;
printf("b = %d\n",b); //b = 100
fun8(); //a = 101
int c = fun8(); //a = 102 用普通变量接函数返回值,接到的是一个值
printf("c = %d\n",c); //c = 102
c = 200;
fun8(); //a = 103
fun8() = 300; // a= 104 函数作为左值使用
printf("b = %d\n",b); //b = 300
fun8(); //b = 301
return 0;
}
函数返回值是引用,不能返回栈上的引用,可以返回静态变量和全局变量
//定义一个全局变量 p
int p;
int func1(int r) //以返回值的形式返回函数值
{
p = r++;
printf("p = %d\n", p);
return p;
}
int& func2(int r) //以引用形式返回函数值
{
p = r++;
printf("p = %d\n", p);
return p;
}
int &func3()
{
static int k = 10; //定义一个静态局部变量
k++;
printf("k = %d\n", k);
return k;
}
int main()
{
int a = func1(10);
int &b = func2(10);
printf("a = %d,b = %d\n",a, b);
int &c = func3(); //k = 11
printf("c = %d\n", c); //用引用接函数返回值 c = 11
c = 100;
printf("c = %d\n", c); // c = 100
func3(); // k = 101
//函数作为左值使用
func3() = 200; // k = 102
func3(); // k = 201
return 0;
}
6.1常引用
int main()
{
const int a = 10;
int c = 100;
//int &b = c; 普通引用
const int &b = c;
b = 200;
return 0;
}
常引用不能通过引用改变被引用的值。
6.2常引用初始化
int main()
{
//1. 用变量初始化
int pa = 10;
const int &pb = pa;
printf("pb = %d\n", pb); // pb = 10
//2. 用常量初始化
{ //const int *const pb
const int &pb = 100;
int *p = (int *)&pb;
*p = 200;
printf("pb = %d\n", pb); //pb = 200
}
return 0;
}
注:用常量进行初始化时,编译器会为常量分配一块空间,将常量的值复制到这个空间里,然后常引用作为这个空间的别名。
如有欠缺或不足请留言,谢谢!