<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
為了題目的準確性和我們一般學習過程中的習慣,這裡所有的題目程式碼都是在 X86 環境(32 位平臺)下執行的。
#include <stdio.h> int main() { int a[5] = { 1, 2, 3, 4, 5 }; int* ptr = (int*)(&a + 1); printf("%d,%d", *(a + 1), *(ptr - 1)); return 0; } //程式的結果輸出什麼?
我們先研究 ptr 指標變數裡面儲存的是什麼。&a+1 表示取出整個地址並向後跳躍一個陣列型別的大小,也就是指向了陣列最後一個元素 5 的後面一塊陣列型別大小的空間。
但是我們想要把這個地址交給指標變數 ptr 是不行的,因為型別不一樣(&a+1 是一個陣列指標型別,prt 是一個整形指標型別),所以我們在 (&a+1) 之前 (int*) 來強制型別轉換。這樣我們搞清楚了 ptr 指標變數裡存的是什麼。
那麼現在來看輸出部分。*(a+1) 是比較簡單的,a 是首元素地址,a+1 是第二個元素地址,對其解除參照得到第二個元素 2 ,這是毋庸置疑的答案。對於 *(ptr-1) ,我們知道 ptr 裡面存放的地址位置,並且知道 ptr 是一個整形指標,ptr-1 相當於向前跳躍一個整形型別的大小,即指向陣列最後一個元素 5 的位置。對其解除參照就能得到元素 5 。
故最後的輸出結果為: 2,5 。
#include <stdio.h> struct Test { int Num; char* pcName; short sDate; char cha[2]; short sBa[4]; }*p; //如下表表示式的值分別為多少? //已知,結構體Test型別的變數大小是20個位元組 int main() { printf("%pn", p + 0x1); printf("%pn", (unsigned long)p + 0x1); printf("%pn", (unsigned int*)p + 0x1); return 0; } //程式最後輸出什麼?
我們注意觀察結構體的定義,定義了一個結構體指標變數 p 。
p+0x1 非常簡單,0x1 就是 1,只不過是以十六進位制的格式書寫的。這與我們經常習慣使用的指標計算一樣,p 是一個結構體指標,那麼 p+1 理當向後跳躍一個結構體型別的大小,即指向了結構體空間的後一個結構體空間的位置。並且我們知道 p 是一個全域性變數,全域性變數預設初始化為 0 ,那我們便可以知道,p=0 ,p+1=20 。而 %p 是一個十六進位制的列印格式,所以結果輸出:00000014 。
(unsigned long)p + 0x1 似乎更簡單一些。p 型別轉換成了一個長整形,那麼就代表 p 不再是一個指標,它存放的 0 就是單純意義上的數位。所以 0 + 0x1 就等於 00000001 。
(unsigned int*)p + 0x1 也非常簡單。p 本是一個結構體指標,現在強轉為整形指標,這就代表著 p 進行加減整數的時候步幅由 20 個位元組 變成了 4 個位元組。那麼 p=0 ,p+1=4 是毋庸置疑的。輸出的結果為:00000004 。
#include <stdio.h> int main() { int a[4] = { 1, 2, 3, 4 }; int* ptr1 = (int*)(&a + 1); int* ptr2 = (int*)((int)a + 1); printf("%x,%x", ptr1[-1], *ptr2); return 0; } //程式的結果輸出什麼?
ptr1 的分析與題目一沒有區別,ptr1 存放的是陣列最後一個元素的後面一塊陣列型別大小的地址。並且 ptr1 是一個整形指標。
ptr1[-1] 可改寫成 *(ptr-1) ,因為我們曾經說過,只要是陣列下標的操作都是指標操作,陣列下標的操作只是指標操作的簡寫。那麼此時 ptr1[-1] 就應該指向陣列最後一個元素 4 並對其解除參照得到輸出結果 00000004 。
(int*)((int)a+1) 如何理解呢?a 是陣列名,那麼它就指向了陣列首元素的地址,再將其強制型別轉換,那麼 a 裡面存放的地址就是單純意義上的數位,我們在這個數位的基礎上 +1 ,然後再強制型別轉換成整形指標並存放在 ptr2 中。也就是說,a 本是指向陣列首元素的地址,(int)a+1 就代表地址數 +1 ,地址數 +1 就說明如果是指標的話,它就會指向後一個位元組。再強轉為整形指標,那麼此時 ptr2 指向的地址為:
再對其解除參照就能找到紅色方塊那塊空間的內容,因為是小端儲存,那麼輸出的結果是:02000000 。
需要注意的是,本題使用的列印格式為 %x ,正兒八經的十六進位制,會省略有效數位前的 0 。
#include <stdio.h> int main() { int a[3][2] = { (0, 1), (2, 3), (4, 5) }; int* p; p = a[0]; printf("%d", p[0]); return 0; } //程式的結果輸出什麼?
首先我們注意觀察,二維陣列 a 裡面存放的是三個逗號表示式,我相信有人會在這裡踩坑。即三個逗號表示式,那麼二維陣列 a 裡面的內容應該是 1,3,5 ,0,0,0 (陣列 a 有 6 個元素,內容不夠後面自動補 0 )。
搞清了二維陣列存放的是什麼之後,我們來研究 a[0] 是什麼。a[0] 是二維陣列的第一個元素,這個元素是一個陣列,也就是說,指標變數 p 存放的是二維陣列中的第一個元素,這個元素是一個一維陣列,即拿到了一個陣列名。那麼 p[0] 就很好理解了,p 是一個陣列名,p[0] 就是陣列的首元素,即 1 。故輸出 1 。
#include <stdio.h> int main() { int a[5][5]; int(*p)[4]; p = a; printf("%p,%dn", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]); return 0; } //程式的結果輸出什麼?
我們可以看到,陣列指標 p 存放了二維陣列 a 的首元素地址,這就不難分析了,p 指向的陣列與 a 陣列的儲存內容一樣,但是記憶體分配不一樣。
我們把這兩個空間重疊在一起:
可以看到,&p[4][2] 與 &a[4][2] 相差了 4 個元素,但因為 &p[4][2] 的地址位置比較低,所以兩個相減是一個負數,即 -4 。但我們要以 %p 的形式列印,%p 是一個無符號的數,所以我們便得知結果應該是一個非常大的十六進位制數。那麼 -4 的原反補為:
所以前者的輸出結果為:fffffffc 。
我們知道,指標(地址)相減,得到的是相差的元素個數,上面我們也講過。那麼 %d 是一個有符號的列印格式,所以輸出的結果就是 -4 。
#include <stdio.h> int main() { int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int* ptr1 = (int*)(&aa + 1); int* ptr2 = (int*)(*(aa + 1)); printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1)); return 0; } //程式的結果輸出什麼?
*(ptr1-1) 的結果為 10 應該沒什麼意見吧?
*(aa+1) 可改寫成 aa[1] ,也就是二維陣列的第二個元素,這個元素是一個一維陣列,也就是說得到了一個陣列名。將這個陣列名強轉為整形指標存放在指標變數 ptr2 中,這時候就知道了 ptr2 的具體指向位置。(二維陣列在記憶體空間中是連續存放的!)
*(ptr2-1) 就是將 ptr2 向前跳躍一個整形型別的大小,並解除參照,即找到了元素 5 ,所以輸出結果為 5 。
#include <stdio.h> int main() { char* a[] = { "work","at","alibaba" }; char** pa = a; pa++; printf("%sn", *pa); return 0; } //程式的結果輸出什麼?
指標陣列 a 存放了三個字串常數(關於字串的常數在往期的部落格中已經介紹過),使用二級指標 pa 來指向這個陣列(char** pa=a;),這就表明 pa 變數存放的是 a 陣列的首元素地址。pa++ 指向了陣列的第二個元素,*pa 毋庸置疑得到了字串常數 "at" 的首元素地址,再通過 %s 列印,就能的得到 at 。
#include <stdio.h> int main() { char* c[] = { "ENTER","NEW","POINT","FIRST" }; char** cp[] = { c + 3,c + 2,c + 1,c }; char*** cpp = cp; printf("%sn", **++cpp); printf("%sn", *-- * ++cpp + 3); printf("%sn", *cpp[-2] + 3); printf("%sn", cpp[-1][-1] + 1); return 0; } //程式的結果輸出什麼?
我們先分析一下 c、cp、cpp 裡面存放的是什麼東西。指標陣列 c 裡面存放有四個字串常數。指標陣列 cp 裡面存放的是四個字串常數的地址。三級指標 cpp 存放的是 指標陣列 cp 的首元素地址。那麼草圖可以畫成:
**++cpp ,因為結合性的原因,我們要先計算 ++cpp,那麼此時 cpp 指向 cp 的第二個元素的地址,然後解除參照得到了 cp 中第二個元素,這個元素又是指向 c 的第三個元素,然後再解除參照得到 c 的第三個元素,這個元素是字串常數 "POINT" 的首字元地址,通過 %s 的形式列印得到 POINT 。一定要注意,++ 這個操作是 cpp 參與運算了,所以下次運算時會從計算後的位置開始。
*--*++cpp+3 ,還是先計算 ++cpp ,此時 cpp 指向 cp 的第三個元素的地址,然後解除參照得到 c+1 ,然後 -- ,c+1 就變成了 c ,然後解除參照得到 c 的首元素地址,在此地址的基礎上 +3 ,就拿到了字串常數 "ENTER" 的第四個字元的地址,然後通過 %s 的形式列印得到 ER 。
*cpp[-2]+3 可改寫為 *(*(cpp-2))+3 ,也就是說,此時 cpp 指向了 cp 的首元素地址,解除參照得到了 c+3 ,c+3 是指向 c 的第四個元素的地址,解除參照便得到了 c 的第四個元素,這個元素是字串常數 "FIRST" 的首元素地址,在此地址的基礎上 +3 便得到字串常數第四個字元的地址,%s 通過這個地址列印便得到 ST 。(此時 cpp 是沒有實質運算的)
cpp[-1][-1]+1 可改寫為 *(*(cpp-1)-1)+1 ,此時 cpp 指向 cp 的第二個元素的地址,解除參照得到 c+2 ,然後 -1 得到 c+1 ,即指向了 c 的第二個元素的地址,解除參照便得到了 c 的第二個元素,這個元素是字串常數 "NEW" 的首元素地址,然後 +1 便指向了字串常數的第二個字元的地址,通過 %s 形式列印便得到了 EW 。
到此這篇關於C語言八道筆試題精講帶你掌握指標的文章就介紹到這了,更多相關C語言指標內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45