03.06 C語言中的sizeof關鍵字能夠計算數組長度嗎?老師說有陷阱是什麼意思?

小虎哥奇異故事


在C語言程序開發中,sizeof() 是一個常用,也是一個非常有用的關鍵字,程序員常常使用它來獲取變量佔用內存的字節數。

稱 sizeof() 為“關鍵字”,是因為雖然 sizeof() 使用起來很像一個函數,但是它與函數還是有很大區別的,這一點我之前的文章討論過。

小技巧:避免“硬解碼”造成的代碼維護困難

例如下面這樣的例子,請看相關C語言代碼如下:

size 就等於 x 在內存中佔用的字節數。在固定的機器平臺,變量 x 是 float 類型,佔用的內存字節數是固定的,例如 float 類型在 pc 上常佔用 4 字節內存空間。

之所以不直接使用 4,而是使用 sizeof(x) 是為了方便以後的維護。可以想象,若以後發現 x 需要使用更長的數據類型 double 才能滿足需求,只需將 float x; 修改為 double x; 就可以了,size 會自己適應修改。

其實不僅C語言,在其他語言的程序開發中,都有這樣一個原則:儘可能的避免硬解碼出現,儘可能的避免重複功能出現,這樣才有利於後期的維護——萬一需要修改代碼,只需要修改一處。

sizeof() 獲取數組長度的“陷阱”

很多時候,利用 sizeof() 還可以獲取數組的長度,例如下面這兩行C語言代碼:

len 此時等於 128,也即數組 str 的長度。但是如果數組不是 char 型的,而是其他類型的,len 還等於數組長度嗎?編寫如下C語言程序:

編譯並執行這段C語言代碼,得到如下結果:

顯然,len 並不等於 arr 的長度 10,而是等於 40。很多C語言初學者看到這裡會感到迷惑,怎麼回事?sizeof(數組名)不是等於數組長度的嗎?

sizeof() 關鍵字從來就不是計算長度的關鍵字,而是獲取變量佔內存空間字節數的關鍵字,這一點要謹記。str 是一個長度為 128 的 char 型數組,它佔用內存字節數恰好等於 128,是因為 str 的每一個元素都是 char 型的,而 char 型佔用一個字節的內存空間,因此此時 str 佔用內存字節數和它的長度恰好是相等的。

再來看數組 arr,它的長度等於 10,但是它的每個元素都是 int 型的,而在我的機器上 int 型變量佔用 4 字節內存空間,所以 arr 一共佔用 40 字節內存空間,因此 sizeof(arr) 等於 40,而不是 10。

獲取數組長度的小技巧

現在知道 sizeof() 有時無法直接獲取數組長度的原因了,我們完全可以如下定義一個方法,用於計算數組長度,相關C語言代碼如下,請看:

sizeof(數組名)計算的是整個數組佔用的內存字節數,而 sizeof(* x) 等價於 sizeof(x[0]),也即數組第一個元素佔用的內存字節數。因為數組中各個元素的類型是相同的,所以 sizeof(* x) 也可以認為是每一個數組元素佔用的內存字節數。上述宏定義就相當於:

數組長度 = 數組所有元素佔用內存字節數 / 每個元素佔用內存字節數

這麼看來, arr_len 就不難理解了。編寫如下C語言程序測試一下 arr_len:

編譯並執行上面這段C語言程序,得到如下輸出:

顯然,arr_len 計算其他類型數組的長度也不在話下。


IT劉小虎


sizeof()只能算出數組定義時規定的容量,但不能用於計算數組長度。

sizeof()是編譯期處理的常量。當代碼寫出int x;的時候,若有sizeof(x)則編譯時就直接按編譯參數指定數據長度替換為常數,比如在32位系統中,這個值是4。當代碼寫出int y[10];的時候,sizeof(y)將是40,即整個數組容器的容量。這些都是常數,運行時是不會變的。

有些教材或學長,會跟學生說用sizeof(y)/sizeof(int)來求出值10說是數組的長度,但實際上那是陷阱,不要這樣做。對於數組來說,定義了能夠容納10個元素,不等於使用者就真的用了10個,他實際上可能只用了8個或是3個,甚至可能是動態使用的,數組的長度是實際使用的元素個數,不是容器容量。數組的長度必須動態計算。

舉個例子,C字符串的長度,就不能這樣求。我們通常定義比如100個字符(不管是什麼編碼的字符)的數組,但實際上真正用到字符串的長度,是要找到第一個'\\0'字符為止的字符數,這個順序查找循環是省不了的(C字符串的效率比其他語言低,主要也是這個原因,像BASIC這類是不用循環即能獲取該數據),要用型如strlen()的函數。


分享到:


相關文章: