变量名
C++中的变量名,比如int n
、Object obj
C++对变量名n
、obj
不做存储,只是用于方便编译成汇编代码,是给编译器看的,是方便人阅读的。
举例:
int n=5;
编译器编译它时,产生类似mov [0x00410FC0],5的指令,即:把5放在该内存地址的空间上。其中并没有出现n,n只是编译时供编译器识别的名字,是一个高级语言抽象出来的概念,在真实执行的程序中并不存在n,至于n的地址是0x00410FC0还是其他的什么,这是由连接器(linker)决定的,连接器把全局变量放在.exe文件中,执行.exe文件时全局变量在类似0x00430000左右的地址。局部变量在栈上,一般地址为0x00120000左右。
地址0x00410FC0并不需要一个地址去存放它,因为在最后产生.exe文件它自己知道它需要的一个值存放在什么地址,所以就在它的二进制代码中把0xffbffb0c硬编码进来了。
原文链接:https://blog.csdn.net/tina_ttl/article/details/52648533
C++中的变量名就是个代号,其就是存储单元上具体的数据。它不是指针,也不是引用。
arr&pointer
int a[10]; //数组名可以转化(当作)为指针,即求a数组第n个元素:a[n]实际上是*(a+n),完成了一次解引用过程。
int *p1 = a; //指向数组a的第一个元素,这个指针的内容的类型为int,p1指针等价于a指针
int (*p2)[10] = &a; //指向一个10个元素数组的指针,这个指针的内容的类型为一个指针(指向了数组具体int元素)也是个指针即上面的p1,所以这个p2是指向指针a的指针,所以要对第一层指针a取地址;在二维数组中,若干个指向指针的指针组成一个数组,即上层维度
//第二句拆开来:
int *temp = a; //定义指向数组的指针
int *p2 = &temp; //定义指向指针的指针
//由于这个指针的内容是一个int[10]数组,所以写为:
int (*p2)[10] = &a;
两者都发生了数组名自动转换为指针(a数组名,转化为指针)
但是区别在于第二句又套了一层指针,主要发生在二维数组上。
建议一切数组操作都从指针角度入手和理解
使用例子(重要):
#include <iostream>
using namespace std;
//传入参数为指针,返回参数为指针
int *test(int *arr)
{
arr[0] = -1;
return arr;
}
//传入参数为指向指针的指针,返回参数也为指向指针的指针
int (*test2(int (*arr)[10]))[10]
//int **test2(int **arr) //也可以这么定义,但是这样后面的所有数组维度声明全部要修改
{
(*arr)[1] = -2; //由于传入参数是指向指针的指针,要想操作指针所指向的指针所指向的数组具体元素,需要两次解引用
//这里这句话等价于:
*(*arr+1) = -2; //注意:多个解引用从内开始运算,所以要先解引用得内层指针,有[]则优先级最高
return arr; //返回的是指向指针的指针,所以直接返回传入的arr即可
}
int main()
{
int a[10];
int *p1 = test(a);
int (*p2)[10] = test2(&a);
cout<<p1[0]<<endl; //or *p1
cout<<(*p2)[1]<<endl; //or *(*p2+1)
}
pointer & reference
符号 | 作为左值 | 作为右值 |
---|---|---|
& |
引用类型声明 | 取地址符 |
* |
指针类型声明 | 解引用符 |
运算表达式的结果是右值,函数参数表是左值
赋值语句右边是右值,左边是左值
void func(int &var){} int main() { int a; func(a); //这里实际上发生了隐式初始化:int &var = a ,所以显然参数入口不用&,函数参数表要用&表示引用声明 }
非常量左值引用(
T&
)只能引用一个左值(只能用一个左值对引用进行初始化)常量左值引用(
const T&
)也可以引用一个右值右值引用(
T&&
)只能引用一个右值(但注意,右值引用本身是左值)函数传参,不改变参数时,尤其是大数据,尽量使用
const T&
(常量引用)好处:
const T&
形参初始化为引用,少了对对象的拷贝- 设置为常量避免对对象的误修改
-
const T&
既可以接收左值也可以接收右值
函数返回为左值则返回类型必须为引用
指针成员访问符
->
,和c中一样引用实质是操作地址指针
引用本身是
const
的,一旦初始化之后引用不能赋值(禁止引用传递)完美引用、引用折叠,见”C++11右值引用产生的一揽子问题“专题
左值,右值,亡值
https://zhuanlan.zhihu.com/p/402251966
https://www.zhihu.com/question/363686723/answer/1976488046
【】
字符串
注意字符串字面量是左值,所以非常量引用(string&)也可以直接引用字符串字面量(string &str ="abc";
)
为什么?因为字符串字面量本质实际是C风格字符串const char[N]
/const char*
,上面语句实际上发生了字符数组到字符串的转换
const
靠里是顶层,靠外是底层
非常量可以向常量转化(变严),反过来不行
引用不能修改,都是const的,所以&const a
等价于&a
,不用写const
对常量的引用:const &a
(引用对象不能修改,引用本身也不能修改;简称常量引用,注意只是简称!)
对常量的引用实际可能引用一个非常量的对象:常量引用仅对引用可参与的操作做出了限定,对于引用的本身是不是一个常量未作限定。
常量指针:int *const a
(指针不能修改)
指向常量的指针: const int *a
(指针指向的内容不能修改)
指向常量的常量指针:const int *const a
(指针和指针指向的内容都不能修改)
若将成员函数声明为const(函数参数表与语句大括号之间加const),则该函数不允许修改类的数据变量。且,const类型的成员函数不能返回非const类型的引用,比如这样就OK,const vector<int>& operator*() const
,如果返回类型去掉const就错了
param
函数中,实参到形参的传递是初始化(用实参来初始化形参),而不是赋值!(显然,引用不能传递,但函数能接收引用)
传参即用实参初始化形参,注意传的是什么。比如传的如果是引用/指针,那么引用的对象是不会触发拷贝/移动构造函数的,因为实际上是传的引用/指针本身而不是对象