2016-01-24 104 views
1

這下面的代碼不能編譯:無法推斷出從初始值設定爲界限多維數組

int main() { 
    int a[][] = { { 0, 1 }, 
       { 2, 3 } }; 
} 

產生的錯誤消息是

error: declaration of 'a' as multidimensional array must have bounds for all dimensions except the first 
int a[][] = { { 0, 1 }, 
     ^

這是由標準規定?如果是這樣,爲什麼呢?我認爲在這裏推斷界限會很容易。

+0

您是否嘗試過用'一[] [2]'? –

+1

簡單,如果你只有'int's考慮。如果你對它有更多的瞭解,看起來並不那麼簡單:內部大括號可以忽略,如果不是,可以調用構造函數,可以執行轉換等等。因此,對於編譯器來說,數組維度根本就不是明顯。另外,普通數組是邪惡的,維度n的多維數組是pow(evil,n)。 ;) – Drop

+0

@Drop我想你已經明白了:) – Lingxi

回答

3

這是由標準規定的嗎?

嗯,是的。

§8.3.4/ 3當幾個「數組」規格相鄰時,將創建一個 多維數組類型;只有指定數組邊界的常量 表達式中的第一個可以省略。在 除了允許不完整對象類型爲 的聲明之外,在函數參數(8.3.5)的聲明 中的某些情況下,可能會省略數組的綁定。當聲明符後面跟着初始化符(8.5)時,數組的綁定也可以省略 。 在這種情況下所結合的從初始 元件的供給(8.5.1)數目(比如說,N)來計算,並且所述標識符的D 的類型是「的NT陣列」。此外,如果在前面的 聲明的實體位於指定了綁定爲 的相同範圍內,則忽略的數組綁定與以前的聲明中的 相同,並且類似地用於定義靜態數據 類的成員。

如果是這樣,這是爲什麼?

首先,數組不能從不完整的類型構造(例如void)。結合的未知的陣列是那些不完全類型之一:

§8.3.4/ 1 ...陣列類型的對象包含的T類型的子對象N一個連續地分配 非空集合。除了以下說明的,如果 常量表達式被省略,的D 標識符的類型是「衍生聲明符類型列表陣列結合的T未知的」,一個不完整的 對象類型。 ...

§8.3.4/ 2的陣列可以從基本類型 之一(除了void)構成,從一個指針,從一個指針到構件,從 類,從枚舉類型,或從另一個陣列。

此外:

§3.9已聲明但不是限定的類,枚舉類型 在某些情況下(7.2),或未知的大小或不完全 元素類型的陣列,是未完成定義的對象 類型。 ...

45)對象類型的未完全定義的 實例的大小和佈局未知。

我覺得這裏演繹界將是非常容易的。

初學者有一個常見的錯誤,那就是編譯器具有魔力。編譯器使用它的信息已經了,它不會創建信息的空氣。如果您要求它創建一個未知大小的對象,它根本無法做到。請參閱以下示例:

只有最內部的尺寸可以省略。推導出數組變量的類型爲 的元素的大小。 元素類型因此必須具有已知的大小。

  • char a[] = { ... };具有元件(例如a[0])大小 1(8位)的,並具有一個未知大小。
  • char a[6] = { ... };具有大小 1的元素,並且具有大小6.
  • char a[][6] = { ... };具有元件(例如a[0],這是一個數組)大小 6的,並具有一個未知大小。
  • char a[10][6] = { ... };具有大小 6的元件並且具有尺寸60

不允許:

  • char a[10][] = { ... };將具有10個元素未知大小的。
  • char a[][] = { ... };將有未知數量的未知數

Source

+1

'char a [];''和'char a [] [6];'是非法的。這些形式只能與初始化器一起使用(然後它並不意味着「未知」,這意味着「從初始化器中推導出來」)。 –

+0

Re。您的最後一段,在這種情況下編譯器有足夠的信息進行演繹,這只是語言規則說編譯器不應該在這裏推論。 –

+0

@MM你不是有點迂腐嗎?我們知道編譯器從初始化器中推導出來(它在這個頁面上重複了好幾次)。用'= {...}'精神上代替';',如果它能幫上忙的話,我會沮喪的是那些問什麼類型的空氣被用來填充代表宇宙膨脹的氣球的人 – user5832387