引用和指针
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了引用和指针相关的知识,希望对你有一定的参考价值。
前面我们讲了引用,这节我们就来看看引用和指针有何区别?又有何相同点。首先我们来看看在 C++ 中,const 什么时候为只读变量?什么时候是常量呢?
关于 const 常量的判别准则有这么几个:1、只有用字面量初始化的 const 常量才会进入符号表;2、使用其它变量初始化的 const 常量仍然是只读变量;3、被 volatile 修饰的 const 常量不会进入符号表。凡是在编译期间不能直接确定初始值的 const 标识符,都被作为只读变量处理。const 引用的类型与初始化变量的类型相同时,初始化变量成为只读变量;不同时,生成一个新的只读变量!
下来我们以代码为例进行分析
#include <stdio.h> int main() { const int x = 1; const int& rx = x; int& nrx = const_cast<int&>(rx); nrx = 5; printf("x = %d\n", x); // 1 printf("nx = %d\n", rx); // 5 printf("nrx = %d\n", nrx); // 5 printf("&x = %p\n", &x); printf("&nx = %p\n", &rx); printf("&nrx = %p\n", &nrx); volatile const int y = 2; int*p = const_cast<int*>(&y); *p = 6; printf("y = %d\n", y); // 6 printf("p = %p\n", p); const int z = y; *p = 7; printf("z = %d\n", z); // 6 printf("p = %p\n", p); char c = 'c'; char& rc = c; const int& trc = c; rc = 'a'; printf("c = %c\n", c); // a printf("rc = %c\n", rc); // a printf("trc = %c\n", trc); // c return 0; }
我们来分析下这个程序,在第 5 行定义了一个 const 修饰的 x,所以 x 会进入符号表,它为常量,但是编译器仍然会在栈上为它分配 4 字节的空间。第 6 行是 const 修饰的引用,所以 rx 只是一个具有只读属性的变量,通过第 8 行的 const_cast 去除 rx 的只读属性,在第 10 行改变了 nrx 的值,所以第 12 - 14 行应该打印出 1, 5, 5。第 16 - 18 行打印出的三个地址值应该是相同的,因为它们都是引用。第 20 行定义的由 volatile const 修饰的变量 y 在本质上也是一个具有只读属性的变量,所以通过第 21 行的 const_cast 会去掉它的只读属性,通过第 23 行的指针操作,会改变它的值。所以第 25 行应该打印出 6。第 28 行定义的 const int z,由于它指向的 y 是被 volatile 修饰的,所以在读取 z 的值时会去 y 的地址空间里读取,通过第 30 指针操作并不会改变它的值,第 32 行应该打印出 6。在第 36 行通过 rc 引用了 c,所以他俩是同一个东西。因为第 37 行的引用是不同类型间的引用,所以它会始终指向的是 c 第一次定义的值。我们通过第 39 行的指针操作,会改变 c 和 rc 的值,但并不会改变 trc 的值。我们来看看编译结果
我们看到编译的结果和我们所分析的是一致的,证明我们的分析是正确的。
下来我们来看看引用和指针的关系,为何理解我们之前所说的“引用的本质就是指针常量”。1、指针是一个变量:a> 值为一个内存地址,不需要初始化,可以保存不同的地址;b> 通过指针可访问对应内存地址中的值;c> 指针可以被 const 修饰成为常量或者只读变量;2、而引用只是一个变量的名字:a> 对引用的操作(赋值,取地址等)都会传递到代表的变量上;b> const 引用使其代表的变量具有只读属性;c> 引用必须在定义时初始化,之后无法代表其它变量。
从使用 C++ 语言的角度来看:a> 引用于指针没有任何的关系。b> 引用是变量的新名字。 c> 操作引用就是操作对应的变量;从 C++ 编译器的角度来看:a> 为了支持新概念“引用 ”必须要一个有效的解决方案。 b> 在编译器内部,使用指针常量来实现“引用”。 c> 因此,“引用”在定义时必须初始化。
在工程项目开发中:当进行 C++ 编程时,直接站在使用的角度看待引用,与指针毫无关系,引用就是变量的别名;当对 C++ 代码进行调试分析时,一些特殊情况,可以考虑站在 C++ 编译器的角度看待引用。
下来我们以代码为例进行分析
#include <stdio.h> int a = 1; struct SV { int& x; int& y; int& z; }; int main() { int b = 2; int* pc = new int(3); SV sv = {a, b, *pc}; //int& array[] = {a, b, *pc}; printf("sv.x = %d\n", sv.x); printf("sv.y = %d\n", sv.y); printf("sv.z = %d\n", sv.z); printf("&sv.x = %d\n", &sv.x); printf("&sv.y = %d\n", &sv.y); printf("&sv.z = %d\n", &sv.z); delete pc; return 0; }
我们在里面定义了一个结构体引用。在第 16 行赋值 a, b, *pc。那么我们打印的结构体里的值就应该为 1,2,3。我们来看看编译结果,看看这样的引用是否被支持
我们再来用引用初始化数组看看是否被支持呢?去掉第 17 行的注释
我们看到它报错了,那么为什么它支持结构体的引用,却不支持数组的引用呢?别忘了它是要兼容 C 语言的特性,在 C 语言中,数组间的每个元素都是连续的,相邻元素的地址差值应该为 4,可是我们的引用的是不同地址处的元素,当然不符合这个性质了。所以在 C++ 中,引用除了数组,其他的都支持。通过对指针和引用的学习,总结如下:1、指针是一个变量,引用只是一个变量的新名字;2、const 引用能够生成新的只读变量;3、在编译器内部使用指针常量实现“引用”;4、编译时不能直接确定初始值的 const 标识符都是只读变量。
欢迎大家一起来学习 C++ 语言,可以加我QQ:243343083。
以上是关于引用和指针的主要内容,如果未能解决你的问题,请参考以下文章
我在这 1 行代码中的语法有啥问题(指针、引用和取消引用哦,天哪)?