2013-08-01 50 views
10

具有靈活數組成員的結構顯然不是要聲明,而是與指向該結構的指針結合使用。聲明靈活數組成員時,必須至少有一個其他成員,並且靈活數組成員必須是該結構中的最後一個成員。靈活的數組成員是否真的有必要?

比方說,我有一個看起來像這樣的:

struct example{ 
    int n; 
    int flm[]; 
} 

然後使用它,我必須聲明指針和使用malloc保留內存結構的內容。

struct example *ptr = malloc(sizeof(struct example) + 5*sizeof(int)); 

也就是說,如果我想我的FLM []數組保存五個整數。然後,我就可以用我的結構 這樣的:

ptr->flm[0] = 1; 

我的問題是,我不應該能夠只使用一個指針,而不是這個?它不僅可以兼容C99之前的版本,而且可以在有或沒有指向該結構的指針的情況下使用它。 考慮到我已經不得不使用malloc與FLM,我不應該只是能夠做到這一點?

考慮這個示例結構的新定義;

struct example{ 
    int n; 
    int *notflm; 
} 

struct example test = {4, malloc(sizeof(int) * 5)}; 

我甚至可以使用替換方式相同的柔性陣列成員:

這會還工作嗎? (提供上面的示例定義notflm)

struct example test; 
test.n = 4; 
notflm = malloc(sizeof(int) * 5); 
+0

[C中的靈活數組成員可能重複?](http://stackoverflow.com/questions/246977/flexible-array-members-in-c-bad)。靈活的數組是C99的一部分;指針不是也可能有可移植性問題。 –

+5

主要區別在於靈活的數組成員允許您在一個連續的塊中分配整個結構。如果你想複製結構,只需計算它的大小並做一個副本。而用指針,你必須複製結構本身,但也複製內部數組。 –

+1

@TedHopp用什麼可以想象的方式,你可能會認真地說,指針不是C99的一部分? –

回答

23

指針不是數組。選擇使用哪個的基本原因與數組與指針總是一樣。在柔性陣列成員的特殊情況下,您可能會偏好使用指針的原因如下:

  • 降低存儲要求。指針會通過(通常)4或8個字節擴大您的結構,如果您單獨分配指向的存儲而不是單獨調用malloc,則您將花費​​更多的開銷。

  • 提高訪問效率。一個靈活的陣列成員位於距結構基底不變的偏移處。指針需要單獨的解除引用。這會影響訪問它所需的指令數量和註冊壓力。

  • 分配成功/失敗的原子性。如果分配結構併爲其分配存儲空間以指向兩個單獨的步驟,那麼在故障情況下清除的代碼將更加醜陋,因爲您有一個成功,另一個失敗的情況。這可以通過一些指針算術來避免,它們都可以從同一個malloc請求中分離出來,但是由於對齊問題,很容易導致邏輯錯誤並調用UB。

  • 避免需要深度複製。如果使用靈活數組而不是指針,則可以簡單地使用memcpy(不分配,因爲賦值無法知道靈活數組的長度)來複制結構,而不必複製指向的數據並修復指針在新的副本。

  • 避免需要無深度。這是非常方便和乾淨的,只需要一個對象而不是free指向數據。當然,這也可以通過上面提到的「雕刻單個malloc」方法來實現,但靈活的數組使得它更容易且更不容易出錯。

  • 當然還有更多的理由......

+0

+1個不錯的理由列表,我正在尋找這個[回答]的好處總結(http:// stackoverflow。com/a/20221073/1708801),但我沒有發現任何真正偉大的東西,我將鏈接到這個答案以及B/C這比我迄今爲止發現的任何東西都要好。 –

0

這些概念是絕對沒有必要爲你指出你自己。

您演示的兩者之間的差異是數據在內存中的位置。

在靈活數組的第一個示例中,您的元數據和數組本身位於同一個內存塊中,如果必須,可以作爲一個塊(指針)移動。

在第二個示例中,元數據位於堆棧上,而您的數組位於堆中的其他位置。爲了移動/複製它,您現在需要移動兩塊內存並更新元數據結構中的指針。

當您需要放置一個數組並且它的元數據在空間上一起存儲在內存時,通常使用靈活大小的數組。

一個例子,這是絕對有用的例如,當一個數組放在一個文件中的元數據 - 你只有一個連續的內存塊,每次你加載它將(很可能)被放置在一個不同的您的虛擬機的位置。

+1

陣列數據在很多情況下可能位於結構數據之後。這將允許使用單個分配,*但是*任何時候結構被加載,移動或複製時,都需要更新指針。 – supercat

相關問題