首先看这个:
#include <stdio.h>
#include <iostream>
using namespace std;
int main() {
int a[2] = {1, 2};
cout << "The address of int_array: " << endl;
cout << a << " " << &a << endl << endl;
double b[2] = {1.2, 1.3};
cout << "The address of double_array: " << endl;
cout << b << " " << &b << endl << endl;
char c[2] = {'a', 'b'};
cout << "The address of char_array: " << endl;
cout << c << " " << &c << endl << endl;
int d[5] = {1, 2, 3, 4, 5};
int dd[5] = {6, 7, 8, 9, 0};
int j = 2, k = 1, i = 3;
cout << d[i] << " " << i[d] << endl << endl;
//this code is so strange, but in fact, d[i] = *(d + i) = *(i + d) = i[d].
return 0;
}
这里发现,a和&a好像是一样的,还有char类型的怎么就不一样?
首先是关于a和&a:
#include <stdio.h>
int main() {
int a[5] = {1, 2, 3, 4, 5};
printf("a = %p\n", a);
printf("&a = %p\n", &a);
printf("a + 1 = %p\n", a + 1);
printf("&a + 1 = %p\n", &a + 1);
return 0;
}
显然,a是数组第一个元素的地址,而&a指的是整个数组(两者长度根本不同)
后来自己写了些东西:
#include <iostream>
using namespace std;
int main() {
int a[5] = {305210130, 1164203589, 2023197048, 4, 5};//前三个数字在十六进制中表示分别是12312312、45645645、78978978,这样写主要为了测试方便
int *ptr1 = (int *)(&a + 1);
int *ptr2 = (int *)((int)a + 1);
for (int i = 0; i < 20; i++) {//01
cout << hex << *(int *)((int)a + i) << dec << ' ';
}
cout << endl << endl;
cout << "&a + 1 : " << &a + 1 << endl;//02
cout << "*(&a + 1) : " << *(&a + 1) << endl;//03
cout << "**(&a + 1) : " << **(&a + 1) << endl;//04
cout << "*(a + 5) : " << *(a + 5) << endl;//05
cout << "(int *)(&a + 1) : " << (int *)(&a + 1) << endl;//06
cout << "*((int *)(&a + 1)) : " << *((int *)(&a + 1))<< endl;//07
cout << "*ptr1 : " << *ptr1 << endl;//08
cout << "ptr1 : " << ptr1 << endl;//09
cout << "ptr1[-1] : " << ptr1[-1] << endl;//10
cout << "ptr1[-5] : " << ptr1[-5] << endl;//11
cout << "(int)a : " << (int)a << endl;//12
cout << "(int)a + 1 : " << (int)a + 1 << endl;//13
cout << "(int *)((int)a + 1) : " << (int *)((int)a + 1) << endl;//14
cout << "the address of a's first element : " << a << endl;//15
cout << "*ptr2 : " << *ptr2 << endl;//16
cout << "ptr2 : " << ptr2 << endl;//17
cout << "the hex of *ptr2(*ptr2 = (int *)((int)a + 1)) : " << hex << *ptr2 << dec << endl;//18
ptr2 = (int *)((int)a + 3);//19
cout << "the hex of *ptr2(*ptr2 = (int *)((int)a + 3)) : " << hex << *ptr2 << dec << endl;//20
return 0;
}
现在来试着解释一下,解释点对应代码中的注释序号:
01、
这篇博客里对数据的储存做了很好地说明,可以解释这一点
我的电脑用的显然是Little Endian,这么一来,
实际数据为:(十六进制下)
12 31 23 12 45 64 56 45 78 97 89 78 00 00 00 04 00 00 00 05
内存中的数据应为:(第一行是标号,第二行是数据,同样在16进制下)
0x22ff————2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44
12 23 31 12 45 56 64 45 78 89 97 78 04 00 00 00 05 00 00 00 ?? ?? ?? ??
另外一点要了解的是,
*(int *)((int)a + i)的意思,(int)a将a的地址转化成int类型(注释12), 然后(int)a + 1是地址加一,这个一是真正的一,不按照int的大小加四(注释13),
(int *)((int)a + i)再将int类型的地址转化为指向int的地址(也就是16进制),也就是0x22ff31(注释14),最后取内容。
那么输出结果也就明白了:
0x22ff30: 12312312
0x22ff31: 45123123
0x22ff31: 56451231
.
.
.
注意高位的零被省略了:
0x22ff3a: 00047897——>47897
02、
这里指出了&a的含义:依然是数组的地址(特殊的地址),但是表示了长度,所以后面的加一直接加上了一个数组的长度(也就是20, 转化为十六进制就是14),输出就是0x22ff30 + 14;
03、这里就说明了02中&a的特殊性,相当于自己指向自己?所以取内容仍然是自己;
04、取两次,取第一次是地址,再来一次是地址上的内容;
05、这里是为了验证04的正确性;
06到11都是对上述的实验,注意ptr1的类型决定了地址偏移的大小(-1就是-1个int长度);
12到15还行吧,不太难;
16、这个时候ptr2的地址是0x22ff31那么由01中的解释,*ptr2就是45123123,转化为十进制就是1158820131;
17、16中已讲到;
剩下的几个就是对01的验证了。
注意到这么一道题:
这么一来就没什么问题了,&a + 1指的是数组最后一位的下一个地址,而ptr1[-1] = *(ptr1 + (-1)),也就是数组最后一位,内容是5;
而这个时候的数组值为:(注意进制)
00 00 00 01 00 00 00 02 00 00 。。。
在内存中:(注意进制)
01 00 00 00 02 00 00 00 03 00 。。。
这样一来a的地址对应的是上面的第三个00,转化为int,加一(真正的一),也就是第三个00的下一个——02,再将它转化为指向int的,也就是00 00 00 02,真实值(16进制)02000000,也就是2000000。