指针的基本操作(一)
&与*操作符
char ch='a';
char* cp=&ch;
&操作符为取地址操作符,表达式&ch
是一个右值,所以&ch
不能作为可被修改的左值
- 对于左值,一般说法,编译器为其单独分配了一块存储空间,可以取到其地址,比如常见的变量,左值可以放在赋值运算符左边;(也可以在赋值运算符右边)
- 右值指的是数据本身,不能取到其自身地址,右值只能在赋值运算符右边
*为间接引用操作符,表达式*cp
实际上是一个变量,属于左值;
表达式*cp+1
则相当于将指针cp指向的地址下的内容取出并加1再返回,该表达式为右值;
表达式*(cp+1)
是一个变量,属于左值,如果机器的地址总线是32位,则指针占4字节,*(cp+1)
先取出指针指向的地址,地址值向后移动一个单元,获得一个新地址(该地址为cp指向地址的邻接区域),然后返回新地址下的内容。
在C++中,地址的加1是一种广泛意义的增加操作,根据数据类型决定移动的字节个数:
char ch='a'; // 二进制:0110 0001 十进制:97
ch+1; // 二进制:0110 0010 十进制:98
char* cp=&ch; //cp的值是ch的地址:0x00fefcab
//向后移动一个字节
char* cp2=cp+1; //ch地址的下一个地址:0x00fefcac
int num = 6;
int* ip = # //ip:0x012ff714
//向后移动四个字节
int* ip2 = ip + 1; //ip2:0x012ff718
注意,地址0x00fefcab只是内存中某个字节的编号;
指针的基本操作(二)
+ + 和 - - 操作符
先定义一个指针cp
:
char ch='a';
char* cp=&ch;
对于前置操作char* cp2=++cp;
,其汇编方式的执行过程为:
mov eax,dword ptr [cp]
add eax,1
mov dword ptr [cp],eax
mov ecx,dword ptr [cp]
mov dword ptr [cp2],ecx
eax和ecx是常用的寄存器,第一句语句将cp中的信息读取到eax,然后在eax中加1,然后再把结果存储到cp中,第四句将目前cp的信息读入ecx,再借助ecx将信息存储到cp2;
对于后置操作char* cp3=cp++;
,汇编方式的执行过程为:
mov eax,dword ptr [cp]
mov dword ptr [cp3],eax
mov exc,dword ptr [cp]
add ecx,1
mov dword ptr [cp],ecx
明显发现顺序发生了变化,先将cp的信息借助寄存器转存到cp3,再将cp的信息加1存回cp;
- - 与上述过程的操作过程一样,只是增加操作要变成减少;自增运算不只是指针独有的操作,也可用于其他类型的对象。
初步得出规则,前置操作会先对变量进行操作,再返回值;后置操作则先返回变量的值,再对变量执行操作;
++cp
与cp++
是地址的临时表达式(不能获取到这个新对象的地址),只能是右值,注意*(cp++)
和*(++cp)
是可以找到具体对象获取到地址的,属于左值。
间接引用*的优先级小于自增运算,因此*(cp++)
等价于*cp++
,*(++cp)
等价于*++cp
指针的基本操作(三)
关于++++
,----
运算符
编译器在解析符号时,会逐个读入字符,如果该字符可能组成一个符号,那么读入下一个字符,一直到读入的字符不再组成一个有意义的符号。比如:
int a=1,b=2;
int c;
c=a+++b; //处理为a++,再+b
//如果为:
c=a++++b; //处理为a++,++b,不能将两个对象赋值给c,报错
先定义指针cp
:
char ch='a';
char* cp=&ch;
对于表达式++*++cp
,按照优先级分解为++(*(++cp))