
个人认为,操作指针需要清楚两件事情。一、明白在操作的内存地址;二、清楚当前指针移动的步调会有多大,在这一点上就需要与前面的知识结合起来,需要非常清楚指针所指向的数据类型在内存中的大小。
指针运算符&和*
&是取地址运算符,会返回变量所匹配的内存空间的地址。比如说a是一个变量,绑定着一块存储着数据的内存空间。而&a就会把a所绑定的那块数据内存空间的首地址返回来。要是不理会内存管理的知识的话,可以简单的说就是返回a的地址。
*是间接运算符,它的作用就是拿到指针所指向的那块内存空间里面的东西。
个人认为,可以把’&’和’‘两个运算符认为是一组运算符,说白了就是&负责取地址,而负责拿到地址里面的东西。
运算符*的使用举例
例一:读取与修改
1 |
int a = 10; |
p拿到a的地址后,通过*p拿到a所绑定的内存空间里面的数值10,然后还可以直接对该内存空间进行修改,将数值改为500.
例二:注意指针移动的步调
1 |
char a[20] = "You are a student"; |
指针ptr1的类型是char,指针ptr2的类型是int,ptr1指向的是char型数据,ptr2指向的是int型数据。一个char在内存中占一个byte,一个int在内存中占4个byte,所以ptr1移动的步调是一个byte一个byte的移动,ptr2移动的步调是4个byte4个byte的移动。当然,前辈早已经为我们总结了公式——指针移动的内存单元=指针移动的数值*sizeof(指针所指向的数据类型)。
其实最重要还是要理解背后一些实质性的东西。那么指令ptr2 += 5;执行后会有怎么样结果呢?
例三:二级指针的误区
1 |
char a[20] = "You are a student"; |
程序输出的结果会是什么?Y和o,还是Y和a?
指针p指向字符串的内存空间,类型为char,移动步调为一个byte。而指针ptr指向指针p所在的内存空间,类型为char*,其移动步调应该为4个byte。所以当执行ptr++的时候,的确是移动了4个byte,但是移动的内存空间是存储着指针p的内存空间,而不是存储着字符串的内存空间,这是两块不同的内存空间哟!要是无法抽象理解的话,可以看看前面指针的内存布局。在VS2013中,这会被提示是一个非法操作,因为你不知道存储着p的那块内存空间是什么东西,或者什么东西也不是!
运算符&的使用举例
例一:取地址加运算的陷阱
1 |
int a[5] = {1,2,3,4,5}; |
对于这种陷阱,个人觉得,要是我们对程序稍微修改一下,是不是会更清楚呢?
1 |
int a[5] = {1,2,3,4,5}; |
这样是不是会更加清晰一点?指针ptrTemp指向的数据类型为int()[5],移动的步调为sizeof(int()[5]) = 5*4 = 20个byte。也就是说,每次会移动一个长度为5的整型数组的大小。而ptr指向的数据类型为int,移动的单位为sizeof(int)=4个byte。所以当赋值之后,ptr实际上指向的是a[5]后面的一个内存单元,所以当ptr-1的时候,退后4个byte的长度,正好指着a[5]。
可能要有人觉得,指针不就是数组吗?至少我本人就犯了这个错误犯了很长时间。数组与指针,相似而不相同,往后再慢慢介绍!
小结
正如前面所说,对指针的操作,其实就三件事情。忽略运算符的话,就是两件事情。一、明白指针操作的是内存地址,清楚当前操作的内存空间。二、清楚当前指针所指向的数据类型,理解指针移动的单位,一个类型为T的指针的移动,以sizeof(T)为移动单位。理解好这两点就可以了,我个人觉得。




近期评论