C語言函數不能返回數組,但可以返回結構體


為什么C語言函數可以返回結構體,卻不可以返回數組?有這樣的問題並不奇怪,因為C語言數組和結構體本質上都是管理一塊內存,那為何編譯器要區別對待二者呢?

C語言函數為什么不能返回數組?

在C語言程序開發中,我們不可以編寫下面這樣的代碼:

char f(void)[8] {
 char ret;
 // ...fill...
 return ret;
}
int main(int argc, char ** argv) {
 char obj_a[10];
 obj_a = f();
}

 

這其實就是不能在C語言函數中返回數組。但是如果將數組定義在結構體里面,就可以將其返回了,例如下面這段C語言代碼,請看:

struct s { char arr[10]; }; struct s f(void) { struct s ret; // ...fill... return ret; } int main(int argc, char ** argv) { struct s obj_a; obj_a = f(); }

 

結構體 s 只有一個數組成員 arr,顯然,函數可以返回結構體,即使結構體只有一個數組成員,這是為什么呢?

C語言沒有嚴格意義上的“數組類型”

基本上,C語言中的數據結構可以分為兩類,第一類數據結構可以被賦值,而第二類數據結構不可以被賦值,數組屬於第二類數據結構。

除了數組,還有其他第二類數據結構嗎?我想基本上沒有了,除非把函數算上。

與函數不能返回數組密切相關的事實是,C語言沒有嚴格意義上的“數組類型”。可能從C語言代碼角度來看,似乎有數組類型的變量,但是如果嘗試將該變量像其他變量一樣使用,得到的實際上是指向數組第一個元素的指針。例如下面這段C語言代碼:

char a[10], b[10]; a = b;

這並不能把數組 b 的內容拷貝給數組 a,實際上,上面兩行C語言代碼相當於下面這一行:

a = &b[0];

顯然,左邊是數組 a,而右邊其實是一個指針。即使數組在某種程度上可以看作能夠被賦值,但我們有很大幾率得到類型不匹配,例如下面這段C語言代碼:

a = f();

這里假設 f() 是一個返回數組的函數,它的核心C語言代碼如下:

char ret[10]; /* ... fill ... */ return ret;

不過按照前面所說的,其實上面的返回語句相當於下面這一句:

return &ret[0];

同樣的,我們若是嘗試將數組賦值給 a,最終實際得到仍然是將指針賦值給 a,熟悉C語言語法的讀者應該能夠看出不妥之處。

 

為什么把數組塞入結構體,情況就不同了呢?

文章開頭提到,雖然C語言的數組不可以被賦值,但是將其塞入結構體就可以賦值了。這是什么原因呢?

其實這涉及到C語言的設計初衷,以及相關的一些發展歷史了。C語言在語法和語義上與機器硬件很接近,它的基本操作可以被編譯為一個或者幾個機器指令,占用若干個處理器周期。

C語言中的數組是特殊的,它與指針一直都是非常曖昧的。這種曖昧的關系從C語言的前身B語言就開始了,並一直延續至今,而今天的結構體語法最初並不是包含在C語言中的。

因為C語言數組與指針的曖昧關系,編譯器也很難區分它們,所以我們不可能為C語言數組賦值。而且由於“賦值”操作也屬於C語言的基本操作,為了貼合硬件,要求其必須在幾個處理器周期完成,所以單個的“賦值”運算符 = 基本上不可能擴展到需要幾千乃至幾萬個機器周期,以對成千上萬個數組元素賦值。

基於這樣的原理,早期的C語言其實連結構體賦值都是不支持的。

到這里,相信不少讀者又有疑問了,既然C語言的基本操作需要控制在少量的機器周期內,那為什么結構體賦值卻是支持的呢?畢竟C語言中的結構體也是可以包含多個字節信息的。

 

正如前文所說,早期的C語言的確不支持結構體賦值,但是在后來的發展中卻增加了結構體賦值能力。對此只能說是結構體幸運,“將C語言基本操作控制在少量機器周期內”只是一個准則,而不是限制。

要知道,C語言結構體通常很小,只有幾十到幾百字節,增加結構體賦值能力無疑能夠大大方便程序員編寫代碼。大多數情況下,結構體賦值操作並不會嚴重“超時”,這其實是一種平衡。

程序設計語言一般都要處理一個天平,天平的兩端分別是機器和程序員,如果追求極致的機器效率,將編程語言設計的十分精簡,那么程序員就會非常痛苦。因此,即使是C語言,在追求高效率的同時,也要兼顧程序員的感受,所以稍稍違背一些設計准則,增加一些便利操作也是無可厚非的。

小結

C語言不支持數組賦值,更多的原因是C語言本身的特點(貼合硬件)以及一些歷史原因。不過,如果真的希望對數組賦值,也是有一些技巧的,例如將數組塞入結構體。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM