爲什麼int a[5] = {1,2,3,4,5,6}
發出警告,而int a[5] = {1,2,3,4,5}; a[5] = 6;
不?爲什麼溢出數組初始化會發出警告,但溢出賦值不會?
當我最初聲明數組大小爲5時,這是否是一個很好的做法?
如果我不知道數組的大小,該怎麼辦?我可以聲明這樣的int a[]
嗎?
爲什麼int a[5] = {1,2,3,4,5,6}
發出警告,而int a[5] = {1,2,3,4,5}; a[5] = 6;
不?爲什麼溢出數組初始化會發出警告,但溢出賦值不會?
當我最初聲明數組大小爲5時,這是否是一個很好的做法?
如果我不知道數組的大小,該怎麼辦?我可以聲明這樣的int a[]
嗎?
int a [5] = {1,2,3,4,5,6}爲什麼int a [5] = {1,2,3,4,5}; a [5] = 6;纔不是?
由於您知道初始化語句中變量的大小,該賦值給出警告,並且顯然違反了聲明的大小。你沒有a
中a[6] = 6
這行的數組大小,所以對於編譯器來說,它看起來沒問題。當然,警告的級別從編譯器變爲編譯器,並且對於某些編譯器,您可以指定額外的警告。
例如,使用gcc,您可以使用標記-Wextra
和-Wall
來獲取很多警告。接收警告是一件好事,因爲編譯器可以幫助您找到可能的警告,而無需調試代碼。當然,如果你解決這些問題:-)
它們纔是好它是一個很好的做法,以做到這一點時,我最初宣佈陣列 大小爲5?
這是從來沒有分配到內存中的一個地方,你沒有宣佈一個整數一個很好的做法 - 這個值被寫入在那裏你不能確定,而且可以覆蓋另一個變量,或更糟糕的是,部分覆蓋了一些其他變量或堆棧。由於這種內容與編譯器和編譯器不同,正如@PascalCuoq所指出的那樣,它被稱爲未定義的行爲,這是你想要不惜一切代價避免的東西。當然,由於它是未定義的,可能會發生這樣的情況,即你的程序在聲明之後執行得很好,但這是一個非常糟糕的做法。
但是,初始化一個固定大小的數組沒有任何問題,如果它不會改變的話。您應該避免幻數並使用常量,例如MAX_NUMBER_OF_PERMUTATIONS
或CURRENCIES_SIZE
。
我可以這樣聲明:int a []?
將它聲明爲int a[]
是初始化固定數組和編譯器可以指定元素數的簡寫。例如:
int a[] = {1,2,3}; //this is good
int b[3] = {1,2,3}; //same from above
在過去,通常是宣佈int a[];
但它在每一個編譯器不工作,所以應儘量避免。 (感謝@PascalCuoq指出這一點)
如果我不知道我的數組的大小?
如果你不知道你的數組的大小,你應該聲明爲指針,像int * a
和使用malloc
,realloc
,calloc
和類似的系統調用自己管理的內存。請做好工作並瞭解free
- 世界將在稍後謝謝你。如果您正在尋找動態內存分配,您應該閱讀指針而不是數組。
int a [5] = {1,2,3,4,5,6}爲什麼int a [5] = {1,2,3,4,5}; a [6] = 6;纔不是?
警告只是編譯器試圖幫助你。每次你做錯了事,編譯器都不必警告。編寫不正確的程序的方法太多,編譯器無法警告所有的程序。
當我最初宣佈數組大小爲5時,這樣做是否是一種好的做法?
No.當a
是大小5的陣列,訪問a[6]
或a[5]
調用未定義的行爲(譯註:它是非常差)。關於未定義行爲的傳統說法是,它允許編譯器使守護進程飛出你的nose:
在1992年初在該組的討論,經常說 「當編譯器遇到[給定未定義構造]它是合法的,它使惡魔飛出你的鼻子「(暗示 ,編譯器可以選擇任何任意離奇的方式來解釋代碼而不違反ANSI C標準)。
因此,總之,總是avoid未定義的行爲在你的C程序中。
如果我不知道陣列的大小怎麼辦?我可以像這樣int a []聲明它嗎?
不,你不能。在聲明數組時,您必須知道數組的大小。 int a[];
會聲明一個不完整的數組,這不是你想要的(here是一個關於不完整類型的鏈接,但是如果你想要訪問五元素數組的第六個元素,你只是不想聽到不完整的類型然而)。如果您不知道最終需要的尺寸,請了解malloc()
和realloc()
。
感謝您的明確解釋。然而,我仍然對'int a []'部分感到困惑,因爲它與Neil的回答相矛盾:「你可以聲明數組爲'int a []',但是你聲明的只是一個指針到一個數組「。 – mushroom 2013-04-26 17:01:46
@jon這正是爲什麼你應該讓自己一本好書,而不是從互聯網上的陌生人的答案分段學習C.這一個晚期版本應該沒問題。如果你已經閱讀過,我可以爲你找一本好書:http://en.wikipedia.org/wiki/The_C_Programming_Language – 2013-04-26 17:04:13
「不,它調用未定義的行爲(翻譯:它非常糟糕)。」你能否詳細說明或給我一個鏈接?我不知道這是一件壞事。 – fotanus 2013-04-26 17:05:56
的問題:爲什麼
int a[5] = {1,2,3,4,5,6};
給予警告,同時
int a[5] = {1,2,3,4,5};
a[5] = 6;
不?
這實際上是一個很好的問題,我沒有一個很好的答案。
至於C語言標準說什麼,初始化是約束違反,這意味着符合標準的編譯必須問題進行診斷,並可以拒絕該方案。 (海灣合作委員會這樣做,-pedantic-errors
選項,我建議使用)。
在第二種情況下,a[5] = 6;
有未定義的行爲。該語言不需要診斷,但它肯定允許一個,並且足夠聰明的編譯器可能警告它。當編譯器看到a[5]
的賦值時,它知道(或可能知道)a
只有5個元素,並且您試圖訪問第6個元素。海灣合作委員會,至少不這樣做,至少不是我試過的選項。
爲什麼標準要求診斷第一個病例但不是第二個病例?因爲在編譯時總能檢測到第一個錯誤。編譯器有知道a
有多大,因爲聲明正在創建它;它必須爲它分配內存。在這樣的聲明中,編譯時總是知道大小。 (有可變長度數組,但不能使用這種初始化工具。)
在a[5] = 6;
中,編譯器將不得不執行更多的分析來檢測錯誤,這並非總是可能。你可以將其輕鬆地寫:
a[n] = 6;
這將是一樣糟糕,如果n
恰好是5
- 但是編譯器必須確定在編譯時是n
將不得不的價值運行時間來診斷它。編譯器有時可以進行這種分析,但有些情況下理論上不可能。
那麼爲什麼不gcc診斷a[5] = 6;
的特殊情況?這可能只是gcc的開發者選擇投入時間和其他資源的問題。
我非常喜歡你的討論,但我不會說「理論上不可能」警告在運行時可能發生的越界訪問。我只想說,「出於理論上的原因,編譯器製造商必須接受錯誤肯定或者錯誤否定,或者兩者兼而有之,即使他們有最好的診斷意圖。」正如你已經指出''[5]'不是一個困難的情況。 – 2013-04-26 17:46:56
@PascalCuoq:如果用戶輸入的索引值或從文件讀取的索引值,我會說在理論上可能發出編譯時警告,說它超出了界限。你總是可以發出一個警告,說明它可能會超出範圍,但是你可能會在虛假警告中淹死。有些提及停機問題可能適用於此。 – 2013-04-26 19:05:14
我並不是建議引用Halting問題。 「理論上的原因」足夠模糊,說得對,而我覺得Halting問題太多了。事實上,我定期討論這個問題,所以我將它寫下來,以備將來重複使用。無論如何,這肯定不適合這個評論:http://blog.frama-c.com/index.php?post/2013/04/26/Of-compiler-warnings-discussions – 2013-04-26 21:37:33
請注意你的意思是「a [5] = 6;'。 – djechlin 2013-04-26 17:00:21
@djechlin謝謝,是的,我的意思是'a [5] = 6;'。更新。 – mushroom 2013-04-26 17:09:41
任何人都可以給這個更精確的標題? – djechlin 2013-04-26 17:10:05