我在酷殼上看到一篇文章,C語言結構體裡的成員數組和指針,看得感覺讓我真是佩服地五體投地啊。皓哥雖說謙稱自己不是高手啥的,但是寫出這樣的文章來,真是讓我感覺自己的水平真是渣渣!我看完了感覺有點小激動,也想自己講講,試試,看看能不能講清楚那個微博中所敘述的的問題,絕對沒有抄襲的意思。由於我的水平實在有限,寫的可能很糟糕,還請各位見諒!
OK,廢話少說,先來說說一下問題,有這麼一段代碼,
1 #include<stdio.h> 2 struct str{ 3 int len; 4 char s[0]; 5 }; 6 7 struct foo { 8 struct str *a; 9 }; 10 11 int main(int argc, char** argv) { 12 struct foo f={0}; 13 if (f.a->s) { 14 printf( f.a->s); 15 } 16 return 0; 17 }
這個程序會在哪一行掛掉呢?我用的是gcc,我這裡是在第14行掛掉的。為什麼呢?為什麼那個if語句那裡不掛掉,而是在printf語句這裡掛掉呢?
這個我們首先得分析變量是啥?變量是啥,其實就是內存區域的別名!而結構體類型的變量,其實就是一大塊內存區,然後結構體變量名指向的是這塊內存區的起始地址,然後根據變量的類型來不斷向後推出其他變量。比如上面那個str結構體。其實就是一塊4字節內存用來存放int變量len,然後後面的字節用來存放字符數組s。我們可以通過gdb打印出他們的地址,如下圖所示:
這裡結構體變量t和它的第一個成員len的地址都是0xbffff184,而它的s成員的地址就是t的地址+4也就是0xbffff188。OK,通過這樣的敘述不知道大家能不能理解,其實結構體中每個成員的變量的地址其實就是結構體變量的地址加上相對偏移。比如上面例子中s的地址就是t的地址加上4個字節(代表int變量)。
知道了這個概念,我們來分析一下這段程序。
首先從主函數開始,建立了一個f變量,裡面有一個成員是指針a,然後指針a裡面存放的地址被初始化為0。然後在if語句中使用的是f.a->s,它就是找到一個地址,就是s變量的地址,尋找的方式就是先找到結構體變量指針a中存放的地址,然後再對這個地址+4,然後找到這個地址之後並沒有去訪問這個地址所代表的內存空間,所以程序沒有報錯。而在print語句中呢,也是先找到這個地址,然後去訪問這個地址所代表的內存空間,試圖在這個空間中尋找一串字符串並輸出出來。由於a中我們已經初始化為0,所以訪問的內存空間就是0x4的空間,所以程序就會掛掉了!^ o ^