2016-07-07 34 views
1

在C99,有這兩個?:代碼以便與可變長度數組

int main() { 
    int n , m; 
    scanf("%d %d", &n, &m); 
    int X[n][m]; 

    X[n-1][m-1] = 5; 
    printf("%d", X[n-1][m-1]); 
} 

和之間有很大的不同:

int main(int argc, char *argv[]) { 
    int n , m; 
    int X[n][m]; 
    scanf("%d %d", &n, &m); 

    X[n-1][m-1] = 5; 
    printf("%d", X[n-1][m-1]); 
} 

第一個似乎總是工作,而第二個似乎適用於大多數輸入,但爲輸入5 56 6提供了段錯誤,併爲輸入9 9返回了不同於5的值。那麼你需要確保在使用可變長度數組聲明它們之前獲取這些值,或者在這裏還有其他事情嗎?

+4

第二個是明顯的錯誤...因爲'n'和'm'沒有初始化。 'int X [n] [m];'在代碼中使用'm'和'n'的值 - 你不能稍後設置它們,也不能通過稍後更改它們來調整它的大小。 – Dmitri

+0

好的,謝謝,想確保它只是一個有序的東西,而不是我沒有想到的其他東西。 – Austin

回答

4

當第二個工作時,這是純粹的機會。事實證明,它的工作證明,幸好編譯器還不能make demons fly out of your nose

聲明變量不一定會初始化它。 int n, m;在這種情況下同時出現nmundefined值,並試圖訪問這些值是未定義的行爲。如果內存中那些指向的原始二進制數據發生被解釋爲一個大於輸入值nm的值 - 這是非常非常不確定的 - 那麼您的代碼將工作;如果沒有,它不會。你的編譯器也可能已經做了這個段錯誤,或者讓它融化了你的CPU;這是未定義的行爲,所以任何事情都可能發生。

例如,假設編譯器專用於n的內存區域碰巧包含數字10589231,並且m得到了14。如果你之後輸入12的n和6的m,那麼你是金的 - 陣列恰好足夠大。另一方面,如果n得到了4並且m得到了2,那麼你的代碼將會越過數組的末尾,並且你會得到未定義的行爲 - 甚至可能不會中斷,因爲完全有可能存儲在根據您的編譯器/ C標準,您的程序和有效整數都可以訪問數組結尾後的四字節段。另外,nm可能以負值結束,這會導致......怪異的東西。大概。

當然,這一切都是根據編譯器,操作系統,一天中的時間和月相,的所有鬆散和猜測,你不能依賴任何發生的數字初始化到正確的。

另一方面,第一個是通過scanf分配值,所以(假設它沒有錯誤)(並且輸入的數字不是負數)(或零)具有有效的索引,因爲數組保證足夠大,因爲變量已正確初始化。


只是要清楚,即使變量需要是在某些情況下初始化爲零並不意味着你應該依賴於這種行爲。你應該總是明確地給變量賦一個默認值,或者在聲明後儘快初始化它們(在使用類似scanf的情況下)。這使得你的代碼更加清晰,並防止人們懷疑你是否依賴於這種類型的UB。


1:來源:Ryan Bemrose,在聊天

-1

第二個應該會產生錯誤,因爲如果n和m是局部變量,那麼n和m會被初始化爲相當多的隨機值。如果它們是全球性的,則它們的值爲0.

+0

「C++的任何版本」--VLA是C的東西。 C++沒有它們。 – user2357112

+0

噢。你可以使用C++並仍然允許它們,所以我忘記了這一點。 –

4

int X[n][m];裝置聲明一個數組,其尺寸是nm目前具有的值。 C代碼不會展望未來;語句和聲明按照遇到的順序執行。

在你的第二個代碼,你沒有給nm值,所以這是不確定的行爲這意味着任何事情可能發生。

這裏是順序執行的另一個示例:

int x = 5; 
printf("%d\n", x); 
x = 7; 

這將打印5,不7

+2

這篇文章感覺...不僅僅是一點點諷刺和居高臨下,tbh。也許這是對我來說很基本的東西,所以看到它的任何解釋聽起來都很平常。 –

+3

@QPaysTaxes我只是想說清楚,沒有諷刺或謙遜的意圖 –

+0

不夠公平。這可能都在我的腦海中。 –