2010-02-21 78 views
4

對於指針,我對使用char **或char *或* array的聲明和函數參數感到困惑[ n]等。如果一個函數接受一個(* array [n])參數,我會傳遞一個**類型嗎?C/C++中的指針/數組語法(char ** p,* p [n])

我嘗試使用左右規則並知道p是指向char(char ** p)的指針的指針,p是n個指針(* p [n])的數組,但有人說* p [n]和** p基本上是等價的。真的嗎?

回答

5

閱讀C宣言(這是與*和[]變量的一部分)是相當細微的。有一些網站與提示:

一個char**是一個指向(可能是多個)指針(S)到(可能是多個)字符(S)。例如,它可能是一個指向字符串指針的指針,或者是一個指向字符串指針數組的指針。

A char*[]是指向char的指針數組。當你有一個把它作爲參數的函數時,C編譯器會將它「衰減」爲char**。這隻發生在第一層...因此,舉一個複雜的例子,char*[4][]變成char*(*)[4]。閱讀上面的鏈接,以便了解這意味着什麼。

或者你可以做一個(非常合理的)事情,並做一堆typedefs。我不這樣做,但直到你擅長閱讀宣告者,這是一個好主意。

typedef char * stringp; 
void func(stringp array[]) { ... } 
static stringp FOUR_STRINGS[4] = { ... }; 
+0

此外,如果您不是唯一閱讀代碼的人,那麼額外的typedef對其他人的理智也是有益的 - 但當然,不要過分地把它當作相關信息的混亂和分裂(必須結合來自信息源中許多地方的信息來解碼一個結構的含義)也是可讀性。 – Steve314 2010-02-21 09:26:27

0

如果n==0那麼它們引用相同的內存。數組索引基本上是一個指針加偏移量。 *(p[n])將與**(p+n)相同。你可以親眼看到C中的這個簡單,因爲array[4]4[array]會給你同樣的東西。

8

在正確的上下文(即,參數的函數),則下面的聲明是等價的:

int main(int argc, char *argv[]); 
int main(int argc, char **argv); 
int main(int argc, char *argv[12]); // Very aconventional! 

類似的註釋適用於函數定義(其具有嵌段包含在括號中分號的地方)。

在任何其他情況下,符號之間存在重要差異。例如:

extern char *list1[]; 
extern char **list2; 
extern char *list3[12]; 

第一個表示某處存在一個包含'char *'值的不確定大小的數組。第二個說某處 - 可能在這裏 - 有一個包含指向字符指針的值的單個值。第三個人說,在某個地方 - 可能在這裏 - 有12個字符指針的數組。

但是,所有三個列表都可以以相同的方式引用 - 假設它們實際上已經被定義和初始化。

list1[0][0] = '1'; 
list2[0][0] = '2'; 
list3[0][0] = '3'; 

此外,如果將它們傳遞到這樣的功能:

function(list1, list2, list3); 

則該函數可以聲明爲:

void function(char **list1, char **list2, char **list3); 

的陣列(list1的,項目list3)從衰減該數組指向數組的第一個元素;當然,list2已經是一個指向指針的指針了。

void otherfunction(char *list[12]) 
{ 
    ... 
} 

的C編譯器不把該聲明的任何不同於:

void otherfunction(char **list) 
{ 
    ... 
} 

void otherfunction(char *list[]) 
{ 
    ... 
} 

特別

一個詳細的功能,如注意,它沒有進行數組邊界檢查,就功能而言,12也可能不存在。


C99引入VLA(可變長度數組)類型,並且還引入了「靜態」和在陣列邊界的尺寸的符號。您需要閱讀標準以充分理解這些標準。

只需在下面的函數中說數組的大小確實很重要,並且在運行時確定。通常情況下,二維數組除了第一個維外需要指定所有維。

void vla_function(size_t m, int vla[m][m]); 

從標準引用(節6.7.5.3):

void f(double (* restrict a)[5]); 
void f(double a[restrict][5]); 
void f(double a[restrict 3][5]); 
void f(double a[restrict static 3][5]); 

(注意最後聲明還指定對應於在至f的任何呼叫的參數必須是 非空指針指向至少三個數組中的第一個至少三個數組,其他則不指定)