2012-07-17 53 views
-3

我有一個問題,我對我得到的輸出有點困惑。有人能幫我解決這個問題嗎?指針初始化爲一個常數值 - 分段錯誤

`

#include <stdio.h> 

int main() 
{ 
    int *i = 5; 
    char *c = i[1]; 
    printf("%c", *c); 
} 

`

將它正確編譯沒有錯誤。如果它編譯,它會在運行時給出分段錯誤。如果是,由於哪一行。根據我的主要()的前兩行是好的。 printf語句給出了分段錯誤,但我無法證明它的合理性。這裏int *我被初始化爲一個常量。所以我可以將'我'指向其他位置,但不能改變*我。我將'i'的第二個字節分配給char * c,但在這裏我不會改變* i。那麼爲什麼打印* c給出了分段錯誤。這是我的看法。尋找更好的解釋。

+1

這可能是功課嗎? – moooeeeep 2012-07-17 20:07:45

+0

@moooeeeep它不是作業:)它的面試問題。我知道會出現分段錯誤,但我無法給出令人滿意的解釋。 – Kahaly 2012-07-17 21:06:08

回答

1

int *i = 5;創建指向地址 5的指針,而不是數量 5的地址你應該這樣做:

int a = 5; 
int *i = &a; 

而且,由於i是一個指向int,這種行爲是未定義以下:

char *c = i[1]; 
//  ^returns an int, not a char pointer 
+0

但代碼爲main()中的前兩行編譯時沒有錯誤。我的意思是排除printf語句。 – Kahaly 2012-07-17 20:17:03

+0

@Kahaly編譯器不需要甚至警告你這種錯誤。 – moooeeeep 2012-07-17 20:20:32

+0

另請注意,未定義的行爲,由於訪問一個「int」大小的值,超過了作爲數組使用的非數組的末尾...... – twalberg 2012-07-17 20:22:24

2

這樣做int *i = 5;你得到一個指針指向一個invali d內存地址。這很好,只要你不對它進行指針算術,並且不要對它進行解引用。

這樣做char *c = i[1];,你對指針進行指針算術(其中指向的對象是不是數組),並提領,甚至它。這兩個意味着你正在調用未定義的行爲。同時你聲明一個指向另一個指向無效內存地址的指針。

通過執行printf("%c", *c);,您將再次解除引用無效指針地址,該地址將再次調用未定義的行爲。也就是說,任何事情都可能發生,包括分段錯誤。

請注意,您只會觀察到分段錯誤,因爲您正在操作系統上運行,該操作系統知道這種形式的惡意代碼並拒絕其進一步執行。未定義的行爲不保證失敗。事情是,編譯器不需要通知您有關代碼的這些問題。

0

您可以從不是從靜態值初始化指針。你的代碼初始化爲i指向內存地址5,這當然不是你的應用程序內存。做你想做什麼,你需要這樣的:

int x = 5; 
int* i = &x; 

&是運營商的一個獲取INT x,其持有的價值5的地址的地址。至於你的第二行,那是完全無效的。一個指向int的指針就不會支持[]運算符,即使它是一個數組。要麼你想:

  • i值:*i
  • i第一個字節:不要嘗試,除非你有一個很好的理由

然後,你說值賦給一個指針,這也是無效的。您需要再次使用&

+0

我知道這樣做的正確方法。但是代碼片段在採訪中被問到,我不確定這段代碼片段的解釋。代碼爲main()中的前兩行編譯時沒有錯誤。我的意思是排除printf語句。我們可以初始化指向常量的指針。以下聲明完全正確。 'char * ptr =「Hello」;'在這種情況下'int * i = 5;'也應該沒問題。 – Kahaly 2012-07-17 20:19:49

+0

@Kahaly:從編譯器的角度來看?是。從內核的角度來看?編號不知道你的代碼將被允許在它的目標系統上執行什麼。你可能正在寫一個可以做任何事情的啓動加載器。但是在運行代碼時內核處於控制狀態,並拒絕讓您訪問您的進程不擁有的地址5。至於'const char * str =「Hi」',它指向存儲文字字符串的可執行文件的只讀部分。 – Linuxios 2012-07-17 20:26:23

+1

@Kahaly:「未定義的行爲」意味着編譯器不必警告你,你做錯了什麼。 'int * i = 5;'本身的行爲不是未定義的,但是'char * c = i [1];'和'printf(「%c」,* c)的行爲是最確定的因爲'i'和'c'包含無效的指針值。 – 2012-07-17 20:33:23

0

您的代碼有幾個問題。

int *i = 5; 

你初始化指針i地址 5.至少有一對夫婦的這一問題。首先,大多數現代體系結構(如x86)堅持要求多字節類型(如int)對齊,以便它們在偶數地址上啓動。其次,5是非常低的地址值,取決於您的程序可能無法使用平臺(使其成爲無效的地址)。

char *c = i[1]; 

現在你聲明的指針char與後存儲在下一整數地址的整數的值初始化它i(7或9或一些其它的地址,這是因爲已經有問題如上所述;這本身可能導致分段錯誤)。除了輸入問題(表達式i[1]的類型爲int而不是char *)之外,幾乎可以保證i[1]的內容是一個隨機位串,它不對應於有效的存儲器地址。

這就是爲什麼在printf語句中出現分段錯誤; *c正試圖取消引用無效指針。

所以不行,main的前兩行是絕對不是好吧。

+0

'int * i = 5;'它是指向5號起始地址還是指向地址位置5.自從char * ptr =「Hello」以來,我認爲它指向了5號地址;'指向字符串「Hello」的起始地址。整數指針的工作方式不同嗎?所有在一天結束時是整數還是字符的指針都是一個存儲地址位置的整數值。 – Kahaly 2012-07-17 21:01:19

+0

字符串文字不同於數字文字。字符串文字以'char'數組的形式存儲,以便在程序啓動時分配它們,直到程序退出。諸如'5',OTOH之類的數字文字沒有被分配任何存儲,因此沒有地址(它們不是左值)。當你寫'int * i = 5'時,你將文字值'5'分配給'i'。 – 2012-07-17 22:03:06