今天刷題的時候碰到如下的一道題:
int main() {
int array[2019] = { 0 };
array[19] = 2019;
unsigned long offset = (unsigned long)((short*)array + 2019) - (unsigned long)(array + *(unsigned char*)(array + 19));
cout << offset;
}
以上程序的輸出是多少?
仔細一看,這里面各種指針操作,讓人一眼看去就有放棄的沖動。其實不急,按照一層一層的剝絲抽繭,其實也不是那么難。
首先,對於((short*)array+2019)
中,是把array
指針由int
型指針強制轉換為short
型指針,再偏移2019個單位。short
型占2個字節,因而在地址上的偏移量就是2019 * 2 = 4038
;
然后,對於后面的*(unsigned char*)(array + 19)
進行分解:1、array+19
對應得是array[19]
的地址,這個地址存儲的數為2019,其寫成16進制為0x000007E3
,而(unsigned char*)(array + 19)
就是把這個地址轉換為unsigned char
型指針,由於char
型只占1個字節,因而其地址取出來的數只有原來的前1/4內存存儲的數據,即E3
,關於為什么是E3
,而不是00
呢?這個放到下面說。所以,*(unsigned char*)(array + 19)
雖然是char型,但其轉換為數值為0xE3
,即227。之后再(unsigned long)(array + *(unsigned char*)(array + 19))
就相當於array地址偏移227個單元,偏移量為227 * 4 = 908
。因而輸出的offset = 4038 - 908 = 3130
。
關於上面為什么是E3
,而不是00
呢?
這是因為在內存存儲中, 是按照字節從低位到高位存儲的,測試如下:
int main{
int i = 2019;
unsigned char *c;
c = (unsigned char *)&i;
printf("內存中存儲情況:\n");
for (int n = 0; n < 4; n++)
printf(" 0x%x\t%02x\n", &i + n, c[n]);
printf("實際的16進制形式:\n");
printf(" 0x%08x\n", i);
return 0;
}
輸出為: