2011-12-31 101 views
2

當運行此代碼:指針在C,整數指針字符指針

int arr[3] = {2,3,4}; 
char *p; 
p = (char*)arr; 
printf("%d", *p); 
p = p+1; 
printf("%d", *p); 

輸出是2和0。第二個結果是稍微混亂。有人可以解釋爲什麼發生這種情況?

+3

這是功課嗎?如果是這樣 - 相應地標記它。 – littleadv 2011-12-31 11:08:28

+3

當你*運行這段代碼時發生了什麼?推理:在發佈問題之前,向我們展示您嘗試過的內容以及結果是個好主意。 – 2011-12-31 11:11:10

+0

輸出是2和0.第二個結果有點混亂。因此,這個問題。我是一位心臟外科醫生,他正在努力幫助我的兒子完成作業。不幸的是,上帝並沒有讓我們所有人都成爲C專家。 – user1124236 2011-12-31 11:12:57

回答

9

讓我們打破這:

int arr[3] = {2,3,4}; 

創建的3個整數的數組。假設你的系統是32位小尾數,這是它的外觀在內存:

02 00 00 00 03 00 00 00 04 00 00 00 

char *p; p = (char*)arr; 

p現在指向arr但它是一個指針char*。換句話說,p指向02

printf("%d", *p); 

您打印爲intp引用的位置。所以,當你提領p(寫*p)您正在訪問的char(因爲p是類型char*的)由p引用。這是02

p = p+1; 

p現在指向0002後,因爲pchar*。所以當你加1時,它會在內存中移動1 * sizeof(char) = 1 * 1 = 1字節。

printf("%d", *p); 

您打印爲intp引用的位置。因此,當您使用取消引用p(通過書寫*p)您正在訪問p引用的char(因爲p的類型爲char*)。這是00

如果你想打印3而不是0你有你的指針類型更改爲int*而不是char*,通過在內存1 * sizeof(int) = 1 * 4 = 4字節使指針移動。

+0

非常感謝!!! :-) – user1124236 2011-12-31 11:28:05

+3

我還要強調,當讀取'int'類型的值時,就好像它們是'char是合法的,確切的結果取決於實施。在別處編譯時可能會得到另一個結果。 @Cicada必須對平臺做出假設才能提供答案。 – Kos 2011-12-31 11:30:43

+0

假設int是32位,如果平臺是32位或64位(甚至16位),則無關緊要。在一個翻轉的筆記上,對endianness的思考對我來說發生得非常晚,我曾經假設只存在小端類型。來自6502,z80和8088,令人驚訝的是這些數字可以用不同的方式表示。 – bestsss 2011-12-31 17:20:19

4

你得到的結果將取決於你的實現和它的字節順序的大小int

假設32位整型,8位字符和豆蔻端環境(比如86),arr會是這樣的記憶:

<arr[0]> <arr[1]> <arr[2]> 
02 00 00 00 03 00 00 00 04 00 00 00 
^^  ^
p p+1 ... p+4 

如果你把一個字符指針到內存的開始,打印出第一個元素,應輸出2。如果增加該指針,則會輸出0。您需要將其增加幾次以「看」3.

請注意,在具有相同類型大小的大端環境中,您的程序將輸出兩個零,因爲佈局可能是:

<arr[0]> <arr[1]> <arr[2]> 
00 00 00 02 00 00 00 03 00 00 00 04 
^^  ^
p p+1 ... p+4 
1

這裏是一個貼,可以讓你瞭解這個問題更好:http://codepad.org/ClrrwjKY

正如你所看到的,連續整數的值出現三個零分開。這是因爲一個整數是4個字節長,而一個char只有1個字節長。因此,當int數組轉換爲char時,可以逐字節(或char by char)而不是四個字節(int by int)迭代它。

2

這是因爲所謂的endianness

當你創建了int arr[3] = {2, 3, 4};它就會在內存中創建一個數組如下

Big endian: 
    0 1 2  3  4 5 6  7  8 9 10  11 
    +---+---+---+--------+---+---+---+--------+---+---+---+--------+ 
    | | | | ..0010 | | | | ..0011 | | | | ..0100 | 
    +---+---+---+--------+---+---+---+--------+---+---+---+--------+ 

    <--  2  --><--  3  --><--  4  --> 

Little endian: 
     0  1 2 3 4 5 6  7  8  9 10 11 
    +--------+---+---+---+---------+---+---+---+--------+---+---+---+ 
    | ..0010 | | | | ..0011 | | | | ..0100 | | | | 
    +--------+---+---+---+---------+---+---+---+--------+---+---+---+ 

    <--  2  --><--  3  --><--  4  --> 

要了解更多,你需要修改你的程序如下:

int main(void) 
{ 

    int arr[3] = {2, 3, 4}; 
    char *p = (char*) arr; 
    int i; 
    int size = (int)sizeof(arr); 

    for (i=0; i<size ; i++) { 
     printf("%d", *p); 
     p++; 
    } 

    return 0; 
} 

而且,檢查您硬件的字節順序,您可以使用以下功能。僅由1 作爲陣列

void endian(void) 
{ 
     int i = 1; 

     if (*(char *) &i == 1) 
       printf("Little endian \n"); 
     else 
       printf("Big endian \n"); 

     return; 
} 
0

這裏爲「p」爲一個字符指針.. P + 1倍的增量p的電流值是整數,以便通過一個訪問數組一個的每個值,就必須通過2. 遞增字符數組如果整數數組的地址因此1000 ,

arr[0] is at 1000 
    arr[1] is at 1002 
    arr[2] is at 1004 

和改編的值是ARR [0]的地址; 所以最初

p=arr=1000 

當p遞增,p是1001而ARR [1]是1002

..所以爲了訪問所有的值你就必須增加p的值的兩倍每次..