2011-03-04 130 views

回答

45

它們完全相同。 char *argv[]必須讀取爲指向char的指針數組,並將數組參數降級爲指針,因此指向指向charchar **的指針。

這與C中的相同。

+0

感謝您的答覆。你能解釋一下嗎:'...和一個數組參數被降爲一個指針,所以指向指向char或char **的指針。' – Simplicity 2011-03-04 10:03:28

+4

@user:這是一條語言規則。當你用語法'X foo(Y a [])'聲明或定義一個函數時,它實際上變成了'X foo(Y * a)'。看起來像一個函數的數組參數實際上是一個指針。由於'argv'被聲明爲一個數組(指針),它成爲一個指針(指針)。 – 2011-03-04 10:08:10

+0

* char * argv'清除* char *部分的指針。但是,第一個指針從哪裏來? – Simplicity 2011-03-04 10:21:27

3

對於所有實際用途,它們都是相同的。這是由於C/C++對作爲參數傳遞的數組的處理,其中數組衰減爲指針。

3

對於問題的第一部分:

  • 字符** argv的:指針的指針爲char
  • 的char * argv的[]:指針數組

所以問題是指向C類型的指針和數組C []是否是相同的東西。他們一般都不是,但他們是equivalent when used in signatures

換句話說,在你的例子中沒有什麼不同,但重要的是要記住指針和數組之間的區別。

+0

鏈接到C FAQ,但問題是標記爲C++。 – 2011-03-04 09:52:14

+1

C++是C的擴展...因此,適用於C的所有內容都與C++相關。 – 2011-03-04 09:54:14

+1

沒有。有人認爲在C中是非法的,並允許在C++中使用,所以當有些來源說「這是非法的......」並不意味着這適用於C++。 – Mephane 2011-03-04 10:09:45

17

它們確實完全一樣。

陣列要記住的黃金規則是:

「的陣列的名稱是一個指針數組的第一元素」。

所以,如果你聲明如下:

char text[] = "A string of characters.";

然後變量「文本」是指向你剛剛宣佈的字符數組的第一個字符。換句話說,「文本」是char *。當你使用[索引]訪問數組的一個元素時,你實際上做的是將索引的偏移量添加到指向數組第一個元素的指針,然後取消引用這個新指針。因此,下面兩行將初始化兩個變量「T」:

char thirdChar = string[3]; 
char thirdChar2 = *(string+3); 

使用方括號是通過使代碼更可讀的語言提供一個便於學習。但是,當你開始思考更復雜的事情時,這種方式非常重要,例如指向指針的指針。 char** argvchar* argv[]相同,因爲在第二種情況下,「數組的名稱是指向數組中的第一個元素的指針」。

從這裏你也應該能夠看到爲什麼數組索引從0開始。指向第一個元素的指針是數組的變量名稱(黃金法則再次)加上偏移量...什麼都不是!

我和我的一位朋友曾經討論過哪個更適合在這裏使用。使用char* argv[]表示法,讀者可能會更清楚地知道,這實際上是「指向字符的指針數組」,而不是可以被讀作「指向字符指針的指針」的表示法。我的觀點是,後面的這個表示法並沒有向讀者傳達太多的信息。

很高興知道它們完全相同,但爲了可讀性,我認爲如果意圖是一系列指針,那麼char* argv[]表示法會更清楚地表達這一點。

+0

感謝您的回覆。你能告訴我這兩種形式怎麼樣? – Simplicity 2011-03-04 10:10:27

+0

我編輯了我的答案,應該給出更詳細的解釋。 – 2011-03-04 11:09:14

+0

+1方括號 – 2014-09-24 08:39:18

-2

兩者都同樣爲您的使用,除了以下細微的差別:

  • 的sizeof會爲這兩個
  • 另外第二個可能不被重新分配到新的存儲區域不同的結果,因爲它是一個數組
  • 第二個只能使用 有效的索引。如果您嘗試使用超出 數組長度的數組索引,則C/C++未指定它。然而,使用char **,您可以使用從0到0的任何索引。
  • 第二種形式只能用作函數的形式參數。雖然第一個甚至可以用來在棧中聲明變量。
+2

什麼?在OP的要求中,每一個都是incorerct。 – 2012-06-26 21:20:02

2

支架形式是僅在聲明聲明等是有用的:

char *a[] = {"foo", "bar", "baz"}; 
printf("%d\n", sizeof a/sizeof *a); 
// prints 3 

,因爲它知道在編譯時該陣列的大小。當你將一個括號形式作爲參數傳遞給一個函數(主函數或其他函數)時,編譯器不知道在運行時數組的大小是多少,所以它和char ** a完全一樣。我更喜歡char ** argv,因爲它更清晰,sizeof不會像在聲明聲明表單上那樣工作。

-1

C和C++中的TYPE * NAMETYPE NAME[]之間有所不同。在C++中,這兩種類型都不可互換。例如下面的函數是非法的在C(你會得到一個錯誤)++,但法律在C(你會得到警告):

int some (int *a[3]) // a is array of dimension 3 of pointers to int 
{ 
    return sizeof a; 
} 

int main() 
{ 
    int x[3][3]; 
    std::cout << some(x)<< std::endl; 
    return 0; 
} 

爲了使法律只是改變簽名int some (int (*a)[3])(指針的3個整數數組)或int some (int a[][3])。最後方括號中的數字必須等於參數的數字。從數組數組轉換爲指針數組是非法的。從指針轉換爲指向數組數組也是非法的。但是將指針轉換爲指針數組是合法的!

所以請記住:只有最接近解除引用類型簽名並不重要,其他人做(在指針和數組的上下文中,肯定)。

考慮我們有一個爲指針指向INT:

int ** a; 
&a  ->  a -> *a -> **a 
(1)   (2)   (3)   (4) 
  1. 你不能改變這個值,類型爲int ***。可通過功能int **b[]int ***b。最好的是int *** const b
  2. 該類型爲int **。可以通過功能作爲int *b[]int ** b。數組聲明的括號可以是空的或包含任何數字。
  3. 該類型爲int *。功能可能爲int b[]int * b或甚至void * b
  4. 應視爲int參數。我不想陷入細節,就像隱式的構造函數調用一樣。

回答你的問題:在主要功能的真正的類型變元的char ** argv,所以它可以很容易地表示爲char *argv[](但不作爲char (*argv)[])。另外argv的主要功能名稱可能會改爲safely。 您可以輕鬆地檢查:std::cout << typeid(argv).name();(PPC =指針p來燒焦。)

順便說一句:還有一個很酷的功能,帶有數組引用:

void somef(int (&arr)[3]) 
{ 
    printf("%i", (sizeof arr)/(sizeof(int))); // will print 3! 
} 

此外指針什麼可能會被函數隱式接受(轉換)爲空指針。但只有單個指針(不指向指針等)。

延伸閱讀:

  1. Bjarne的Stroustrup的,C++,7.4章
  2. C pointers FAQ
+0

_「在C和C++中,TYPE * NAME和TYPE NAME []之間有區別。」_無義。 _「在C++中,這兩種類型都不可互換。」_不,只有第一種類型實際存在。 _「例如下面的函數是非法的(你會得到一個錯誤)」_這是因爲'int * ar [3]'和'int * ar []'是完全不同的東西。錯誤的信息繼續下去... – 2016-05-06 15:49:40

+0

'clothest'是什麼意思? – Dan 2016-08-02 18:27:18

+0

@丹我的意思是最近的,抱歉 – yanpas 2016-08-02 18:33:27