C++ 引用和指针

引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// C++ 的标准输入,输出头文件
#include<iostream>

void main(){
// 变量的内容保存在特定的内存地址中,而变量名则可以认为是该地址名的别名
int a = 10;
// 在C++中,我们可以通过引用,为一个变量定义新的别名
int &b = a;

// &b表示了让b拷贝a的特性,
// 区别于指针,为p赋值a的地址;
// 实际引用和指针的效果是类似的!
// 指针可以理解为多保存一份变量的地址,变量值是地址,要通过地址取实际的变量值,需要多一步,用*,取地址运算
// 引用可以理解为省略了指针用*取值的步骤,因为引用和原变量名的作用是一致的,就是一个别名,直接通过引用就能
// 拿到实际变量的值(可以认为,引用比指针消耗更少,因为引用不需要再保存一份地址)
int *p = &a;

cout << b<<endl;
system("pause");
}

引用传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// C++ 的标准输入,输出头文件
#include<iostream>

void swap_1(int *a, int *b){
int c;
c = *a;
*a = *b;
*b = c;
}

// 通过引用进行交换
// a和b此时不再是进行值传递,而是通过了引用传递
// 此时的a和b就是调用处的传进来的参数,而不是新的变量
void swap_2(int &a, int &b){
int c;
c = a;
a = b;
b = c;
}

// 引用的主要作用是作为函数的参数和返回值:
// 1,通过引用进行调用,比通过指针调用更加简便,省去了添加*,进行取值
// 2,通过引用作为参数传递,可以直接传递原值,在函数中直接操作源参数,减少参数传递过程中产生的副本,提高效率
// 3,我们可以直接通过引用操作源变量,而指针必须通过取值(*p)才能间接操作,且从可读性上讲,指针更差;
void changeAge(Teacher &t){
t.age = 100;
}

void main(){
int x = 10, y = 20;

cout << "a = " << x << "b = " << y << endl;

// 通过指针进行值交换
swap_1(&x, &y);
cout << "a1 = " << x << "b1 = " << y << endl;

// 通过引用进行值交换
swap_2(x, y);
cout << "a2 = " << x << "b2 = " << y << endl;

system("pause");
}

指针引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58大专栏  C++ 引用和指针pan>
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
void getTeacher(Teacher **p){
// 定义一个指针,并让它指向申请的内存空间的首地址,详单与为其赋值该内存空间地址
Teacher* t = (Teacher*)malloc(sizeof(Teacher));
// p是二级指针,其应该赋值指针变量的地址
//p = &t;
// *p表示取值其地址的内容,其原先保存的是指针的地址,取值则表示取值对应地址的指针变量
// t就是一个指针变量,可以直接赋值给*p
*p = t;
// 一级指针的取值
(*t).age = 20;
t->age = 21;

// 二级指针的取值:先取到一级指针变量值(*p),即指针保存的变量地址,然后取到一级指针指向的变量,及变量地址指向的变量内容(**p)
(*p)->name = "hsh";
(**p).name = "hsh";
}

// 定义一个指针引用,指针引用可以省略前面的*号
void getTeacher(Teacher *&p){
// 引用是指针变量的别名(sizeof引用得出的大小就是对应变量的大小),也可以认为,它就是一个一级指针变量
p = (Teacher*)malloc(sizeof(Teacher));

// 一级指针的赋值操作
p->name = "hsh";
p->age = 20;
}

// 此处如果传递一个一级指针变量,则无法对指针进行初始化
void getTeacher2(Teacher *t){
// 传递一个Teacher变量的地址同样是错误的,因为下面的操作实际是:
// 1,申请一段堆内存;
// 2,将堆内存的首地址赋给t;
// 也就是说,t被重新赋值了,原先传递进来的参数值被抹掉了
t = (Teacher*)malloc(sizeof(Teacher));
t->age = 10;
t->name = "hsh";
}

// 此处操作的是原来地址指向的变量(对其进行初始化)
// 可以影响到传递进来的实参
void getTeacher3(Teacher *t){
(*t) = { "hsh", 20 };
}

void main(){
//Teacher *t;
// 如果传递给二级指针,则必须传递地址
//getTeacher(&t);

// 如果形参是引用,则直接传递变量即可
// t就是一个指针变量,当它传递给一级指针的函数形参时,
// 仍然只是值传递,想要达到引用传递的目的,形参必须是一个二级指针或者指针引用
//getTeacher(t);

// 报错!!!,指针并没有被初始化
// 并不是说,指针作为形参,传递过去就是引用传递,因为指针本身也可以认为是变量的一种,
// 指针要实现引用传递的途径和普通变量是一样的,通过多一级的指针接收或者通过引用形参来接收
//getTeacher2(t);

//cout << t->name << t->age << endl;

Teacher teacher;
// 报错!!!,变量并没有被初始化
// 传递一个没有初始化的首地址作为形参,
// 如果函数中使用了动态内存申请来给指针赋值,同样会错误,因为,此时指针指向的地址已经被重新赋值了
//getTeacher2(&teacher);
//cout << teacher.name << teacher.age << endl;

// 正确!!!
// 只是对原来地址指向的变量进行初始化,则可以
getTeacher3(&teacher);
cout << teacher.name << teacher.age << endl;

system("pause");
}

指针常量与常量指针

1
2
3
4
5
6
7
8
9
10
11
void main(){
int a = 1;

// 指针常量,指针的常量,不能改变地址的指针,但可以修改它指向的内容
// const修饰的是指针,所以指针内容不能改变,即地址不能改变
int const *p1 = &a;

// 常量指针,指向常量的指针,内容不能修改
// const修饰的是变量类型,所以变量类型的内容常量化
const int *p2 = &a;
}

常引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void main(){
int a = 10;
int c = 2;
// 常引用是不能重新赋值的
const int &b = a;
//b = c;
// 跟上面是一样的,没区别
int const &d = a;
//d = c;
//&d = 1;

// 固定为右边的字面量,实际就是定义常量
const int &e = 10;
}
原文地址:https://www.cnblogs.com/lijianming180/p/12433017.html