2012-07-19 30 views
0

首先表達 「&anArray」,我讀到:約在C

  • array
  • &array
  • &array[0]

都將是相同的,只要 「陣列」 是真的是一個數組。 所以,我想:

int main(){ 
    char ar[]={'a','b','c','\0'}; 
    printf("argument: &ar  %s\n",&ar); 
    printf("argument: &ar[1] %s\n",&ar[1]); 
} 

輸出:

argument:&ar abc 
argument:&ar[1] bc 

似乎&ar被當作一個指向第一個元素,而不是指向「AR」,這本身就是一個指針第一個因素,如果我沒有錯。

「的原因,不應該是如何&(指針爲一個字符)被處理,我想:

char a='s'; 
char *pa=&a; 
printf("argument: &pa %c\n",&pa); 

%c的輸出甚至不是一個字符。 也不應該如何處理數組的第一個元素的指針。我想:

char *pa=&ar[0]; 
char **ppa= &pa; 
printf("argument: &pa %s\n", ppa); 

%s的輸出是,這並不奇怪,無義;但爲什麼沒有&ar是廢話?對於如果ar是一個指針,不應該&ar成爲一個指針的指針,因爲是ppa

我的問題:

  1. 簡直是 「&」 數組名前加上時,忽略? 數組名稱只是在這個特別的?
  2. 如果是這樣,編譯器如何驗證以下的標識符「&」是數組的引用?它是否真的在數組列表中搜索它,以便聲明?
+1

數組不是指針,如果這就是你所暗示的'它本身是指向第一個元素指針的指針'。 – chris 2012-07-19 02:07:10

+0

僅供參考:您可以通過突出顯示並單擊「{}」按鈕來格式化代碼。你不需要'
':) :) – Blorgbeard 2012-07-19 02:17:22

+0

@EthOmus - 問問你自己,如果一個指針和一個數組*是完全相同的東西,那麼任何人都會在乎將它們添加到語言中嗎? – 2012-07-19 10:56:00

回答

2

似乎&ar被作爲一個指針到第一元件,而不是一個 指針爲「AR」,它本身是一個指向第一個 元件的指針,如果我沒有弄錯。

誤。 &ar是指向數組ar的指針,但數組ar而不是指向任何類型的指針(它是一個數組),所以&ar不是指向指針的指針。

一個數組是一個連續的對象序列 - 在ar的情況下,它是一組連續的4 char s。 &ar是一個指針這組4個字符,這必然意味着它指向相同的位置&ar[0],一個指向在該組第一char。它具有不同的類型,但是:&ar的類型爲char (*)[4],意思是「指向4個字符數組的指針」,而&ar[0]的類型爲char *,意思是「指向char的指針」。

混亂的出現是因爲在幾乎所有的表達式,ar計算結果爲指向數組(該例外是當它的一元運算符&的操作數或操作者sizeof)的第一個元素。這並不意味着ar一個指針,雖然 - 它不是 - 只是在大多數情況下它的計算結果是一個指針值。

+0

各種來源告訴我,arrayName實際上是指向根數組的第一個元素的指針。要驗證I treid'printf(「argument:* ar%c \ n」,* ar);'%c的輸出是'a',它確認'ar'可以作爲一個指針被取消引用,並且它指向在這種情況下,數組的第一個元素爲'a',如輸出所示。 – EthOmus 2012-07-19 02:38:38

+1

在許多情況下,'arrayName'等價於指向數組的第零個元素的指針;那是真實的。但情況並非如此;它不是一個指針,而是一個數組的名字。它有不同的類型;該類型是數組 - 不是指針。但是在評估時,它會變成一個指針,所以很難理解(並解釋)這種區別。但是,請記住'**數組不是一個指針**',你不會犯太多錯誤。 – 2012-07-19 02:44:07

+0

@EthOmus:你觀察到的東西叫做[Array-to-Pointer decay](http://stackoverflow.com/questions/1461432/what-is-array-decaying)。 – Blastfurnace 2012-07-19 02:45:24

1

printf格式%s表示「相應的參數是指向char的指針。在該位置打印字符串「。爲此,字符串是以空字符結尾的一系列字符。

當你將&ar傳遞給printf時,你傳遞了'a'的地址(儘管類型是錯誤的; printf需要一個指向char的指針,並且你傳遞了一個指向char數組的指針,但它們具有相同的地址),並且printf看到字符串'a','b','c','\ 0',所以它打印出「abc」。如果您通過ar&ar[0],也會發生同樣的情況;那些評估到相同的地址。

當您將&ar[1]傳遞給printf時,您傳遞了指向'b'的指針,並且printf看到字符串'b','c','\ 0',因此它會打印出「bc」。

如果您只想傳遞某個位置的單個字符,請使用%c格式並傳遞一個字符(而不是指向字符的指針)。例如,如果您使用*ar的%c格式,將打印'a',並且如果您使用%c並使用*&ar[1],則會打印'b'。

似乎& AR被作爲一個指針到第一元件,而不是 的指針「AR」,它本身是一個指向如果 我沒有錯的第一個元素。

當在表達式中使用,ar充當指向數組的第一個元素,同爲&ar[0]&arar是相同的地址(數組中的第一個字符與數組的起始地址相同),儘管它們具有不同的類型(指向char數組的指針和指向char的指針)。

輸出用於%c是連字符

它是一種性格,只是不正是您期望,也許不是一個正常的字符或可打印字符。 %c希望傳遞一個字符參數,但是你傳遞了一個地址參數。

如果是這樣,編譯器如何驗證以下的標識符「&」 是在參考陣列,它實際上搜索它在列表陣列 所以對於聲明?

解析比(基本上,爲&之前已知的陣列被認爲是,則&的聯合表達和標識符被評估標識符被標識的)更加複雜。但是,效果是&ar的計算結果與第一個元素的地址相同。

+2

」&ar'的類型是* not *「指向char的指針」,它是「指向4個字符的數組「。 '&ar'和'ar'不會因爲「遺留原因」而被評估爲相同的東西,他們會評估相同的位置,因爲數組的位置和該數組的第一個元素的位置必須一致 - 請注意,它們有不同的類型。從原理上來說,指向「struct」的指針和指向該結構第一個元素的指針評估到同一位置(儘管使用不同的類型)並無不同。 – caf 2012-07-19 05:28:58

+1

@caf:你是對的,我的錯。 C 1999 6.3.2。1 3表示「類型數組」轉換爲「類型指針」,但排除它是一元&(和其他兩種情況)的操作數的情況。我認爲我把「函數返回類型」轉換爲「指向函數返回類型的指針」(6.3.2.1 4),這使「函數」和「函數」相同。我更新了答案。 – 2012-07-19 10:50:10

1

如果您的代碼編譯時沒有警告,那麼您沒有充分利用您的編譯器。它會幫助你,如果你問它這樣做。學習如何使用警告進行編譯,並學習如何解決它所診斷的問題。我編譯下面的代碼與一個或另一個這些命令:

gcc -O3 -g -std=c99 -Wall -Wextra -m64 array-stuff.c -o array-stuff 
gcc -O3 -g -std=c99 -Wall -Wextra -m32 array-stuff.c -o array-stuff 

這對乾淨的代碼與GCC一個很好的起點。的確,-Wall沒有-Wextra也不錯。

這裏是你的代碼的改編(在文件array-stuff.c) - 雖然大部分是不同的:

#include <stdio.h> 
#include <inttypes.h> 

int main(void) 
{ 
    // DC4M = Doesn't compile for me, because I compile with stringent warnings 
    char ar[16] = { 'a', 'b', 'c', '\0' }; // Note explicit size 
    printf("%-18s %s\n", "Code:", "char ar[16] = { 'a', 'b', 'c', '\0' };"); 
    //printf("argument: &ar  %s\n", &ar); // DC4M 
    printf("argument: &ar[1] %s\n", &ar[1]); 

    printf("%-18s 0x%" PRIXPTR "\n", "ar:",  (uintptr_t)ar); 
    printf("%-18s 0x%" PRIXPTR "\n", "&ar:",  (uintptr_t)&ar); 
    printf("%-18s 0x%" PRIXPTR "\n", "(ar+1):", (uintptr_t)(ar+1)); 
    printf("%-18s 0x%" PRIXPTR "\n", "(&ar+1):", (uintptr_t)(&ar+1)); 
    printf("%-18s 0x%" PRIXPTR "\n", "&ar[1]:", (uintptr_t)(&ar[1])); 
    printf("%-18s 0x%" PRIXPTR "\n", "&(ar[1]):", (uintptr_t)(&(ar[1]))); 
    printf("%-18s 0x%" PRIXPTR "\n", "(&ar)[1]:", (uintptr_t)((&ar)[1])); 

    printf("%-18s %zu\n", "sizeof(ar):",  sizeof(ar)); 
    printf("%-18s %zu\n", "sizeof(&ar):",  sizeof(&ar)); 
    printf("%-18s %zu\n", "sizeof(void*):", sizeof(void*)); 
    printf("%-18s %zu\n", "sizeof(ar[1]):", sizeof(ar[1])); 
    printf("%-18s %zu\n", "sizeof(&ar[1]):", sizeof(&ar[1])); 
    printf("%-18s %zu\n", "sizeof(&(ar[1])):", sizeof(&(ar[1]))); 
    printf("%-18s %zu\n", "sizeof((&ar)[1]):", sizeof((&ar)[1])); 

    { 
    char a = 's'; 
    char *pa = &a; 
    printf("%-18s %s\n", "Code:", "char a = 's';"); 
    printf("%-18s %s\n", "Code:", "char *pa = &a;"); 
    //printf("argument: &pa %c\n", &pa); // DC4M 
    printf("%-18s 0x%" PRIXPTR "\n", "&pa:", (uintptr_t)&pa); 
    printf("%-18s 0x%" PRIXPTR "\n", "&a:", (uintptr_t)&a); 
    printf("%-18s 0x%" PRIXPTR "\n", "pa:", (uintptr_t)pa); 
    } 

    { 
    char *pa = &ar[0]; 
    char **ppa = &pa; 
    //printf("argument: &pa %s\n", ppa); // DC4M 
    printf("%-18s %s\n", "Code:", "char *pa = &ar[0];"); 
    printf("%-18s %s\n", "Code:", "char **ppa = &pa;"); 

    printf("%-18s 0x%" PRIXPTR "\n", "&pa:", (uintptr_t)&pa); 
    printf("%-18s 0x%" PRIXPTR "\n", "ppa:", (uintptr_t)ppa); 
    printf("%-18s 0x%" PRIXPTR "\n", "*ppa:", (uintptr_t)*ppa); 
    printf("%-18s 0x%" PRIXPTR "\n", "&ppa:", (uintptr_t)&ppa); 
    } 

} 

這是從Mac OS X 10.7.4機的輸出與一個64位編譯:

Code:    char ar[16] = { 'a', 'b', 'c', ' 
argument: &ar[1] bc 
ar:     0x7FFF6C9DE570 
&ar:    0x7FFF6C9DE570 
(ar+1):    0x7FFF6C9DE571 
(&ar+1):   0x7FFF6C9DE580 
&ar[1]:    0x7FFF6C9DE571 
&(ar[1]):   0x7FFF6C9DE571 
(&ar)[1]:   0x7FFF6C9DE580 
sizeof(ar):   16 
sizeof(&ar):  8 
sizeof(void*):  8 
sizeof(ar[1]):  1 
sizeof(&ar[1]):  8 
sizeof(&(ar[1])): 8 
sizeof((&ar)[1]): 16 
Code:    char a = 's'; 
Code:    char *pa = &a; 
&pa:    0x7FFF6C9DE560 
&a:     0x7FFF6C9DE56F 
pa:     0x7FFF6C9DE56F 
Code:    char *pa = &ar[0]; 
Code:    char **ppa = &pa; 
&pa:    0x7FFF6C9DE558 
ppa:    0x7FFF6C9DE558 
*ppa:    0x7FFF6C9DE570 
&ppa:    0x7FFF6C9DE550 

這是從32位編譯的輸出:

Code:    char ar[16] = { 'a', 'b', 'c', ' 
argument: &ar[1] bc 
ar:     0xC008A670 
&ar:    0xC008A670 
(ar+1):    0xC008A671 
(&ar+1):   0xC008A680 
&ar[1]:    0xC008A671 
&(ar[1]):   0xC008A671 
(&ar)[1]:   0xC008A680 
sizeof(ar):   16 
sizeof(&ar):  4 
sizeof(void*):  4 
sizeof(ar[1]):  1 
sizeof(&ar[1]):  4 
sizeof(&(ar[1])): 4 
sizeof((&ar)[1]): 16 
Code:    char a = 's'; 
Code:    char *pa = &a; 
&pa:    0xC008A668 
&a:     0xC008A66F 
pa:     0xC008A66F 
Code:    char *pa = &ar[0]; 
Code:    char **ppa = &pa; 
&pa:    0xC008A664 
ppa:    0xC008A664 
*ppa:    0xC008A670 
&ppa:    0xC008A660 

W¯¯如果你明白各種數字是如何得出的,你就會很好地理解事物。

請注意,&array[1]被解釋爲&(array[1]);它不同於(&array)[1]的類型和大小。後綴運算符(如數組下標)比一元運算符(如地址(&)和間接運算符(*))的綁定更緊密。