指针:变量的地址。
那地址是什么?首先了解内存编址。
计算机内存是一块存数据的空间,由一系列连续的存储单元组成,每个单元格表示1bit,每八个bit表示一个字节byte。内存寻址的最小单元是一个字节。也就是说,每个byte有一个编号,根据编号就可以找到这个地址。
把这些编号连起来,就是内存的地址空间。这地址空间的大小就和电脑是32位还是64位有关如果是32位,表示cpu支持32位地址空间,即232byte=4*210*210*210=4GB(B表示字节的意思)。而指针是保存地址的,指针必须能表示地址空间最大的地址,因此32位系统,指针是32位(4byte),64位系统,指针是64位(8byte)。
因为不同数据类型大小不一样具体,如char是一个字节,short是2个字节,int是四个字节,因此不同类型的指针在寻址的时候,偏移量不一样,取数据的大小也不一样。什么数据类型的指针,取数据的大小、偏移量(对指针作加减时)即为该类型的大小。举个例子:
cout<<(int)(((int *)0)+4)<<endl;
上面这个代码会输出什么?16.
首先((int*) 0)
是把0转换为int类型的指针,也就是这个指针表示编号为0的地址。紧接着((int*) 0)+4
表示这个地址编号移动4个int类型大小的距离,而int类型是4个字节大小,所以指针+1表示移动4个字节大小,+4表示移动4*4个字节大小。因此地址为16,最后再转为int类型输出。为方便理解,见下图:
/byte | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | … |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
int* | 0 | 1 | 2 | 3 | ||||||||||
char* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | … |
short* | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
其中第一行表示内存空间里的地址编号,每个编号有8bit的空间,对于int类型的指针,每个int类型需要4个字节,因此指针的偏移,每次移动的单位为4个字节,(((int *)0)+4)
则表示int类型的指针移动4个单位,所对应的地址编号(第一行)即为16。同样道理,如果是int(((char*) 0)+4)
,则表示地址编号0开始,移动4个char类型大小的单位,则输出为4;同理,int(((short*) 0)+4)
为8。
为了更好地理解,再来看一个代码:
int a = 0x1234;//0x00001234 小端输出 34 12 0 大端输出 0 0 12
char* p = (char *)malloc(sizeof(a));
p = (char *)&a;
printf("0x%0x\n", *p);
printf("0x%0x\n", *(p + 1));
printf("0x%0x\n", *(p + 2));
这里涉及一个大端小端的概念,大端指数据的高位放在低地址,小端指数据的低位放在低地址。以小端为例分析上述代码。
变量a的十六进制表示为1234,因为24=16,所以十六进制一位数占4bit,则两位十六进制才占一个字节。变量a在内存的储存方式如下(假设a的地址为0):
/byte | 0 | 1 | 2 | 3 | 4 | … |
---|---|---|---|---|---|---|
a | 34 | 12 | 0 | 0 | ||
char* p | 0 | 1 | 2 | 3 |
char* p = (char *)malloc(sizeof(a));
p = (char *)&a;
这段代码是开辟了四个字节的空间(sizeof(a))
=4)给char类型的指针p; 然后让指针指向a的地址.
如上表所示,假设a地址为0,则p为0。由于该指针类型为char,因此它取值和偏移的时候都是以char类型大小为单位进行操作的,也就是*p对p取值时(地址编号为p的数据)只取一个字节的数,根据表可知,地址为0的一个字节内放的数据为34,*(p+1)则为12,以此类推。
如果是大端呢?那就改变一下数据存储方式,高位字节放在低位:
/byte | 0 | 1 | 2 | 3 | 4 | … |
---|---|---|---|---|---|---|
a | 0 | 0 | 34 | 12 | ||
char* p | 0 | 1 | 2 | 3 |
结果显而易见。
最近面试被问了关于指针的代码改错和分析题。虽然之前了解过,但是没有自己总结,所以在思考的时候容易混乱。借此机会总结一下。
面试的时候我基本思路是对的,但是忘记一个概念,就是计算机内存寻址单元是以字节为单位的;sizeof的输出也是以字节为单位的。这些都是最基础的东西,怎么能忘呢?