為什么數(shù)組不可以直接賦值,結(jié)構(gòu)體中的數(shù)組卻可以?
一、前言
二、數(shù)組的各種操作
1. 錯(cuò)誤方式
2. 利用結(jié)構(gòu)體來(lái)復(fù)制數(shù)組
3. 其他復(fù)制方式
三、語(yǔ)言標(biāo)準(zhǔn)和編譯器
1. 數(shù)組和指針的關(guān)系
2. 為什么不能對(duì)數(shù)組賦值
3. 函數(shù)形參是數(shù)組的情況
4. 為什么結(jié)構(gòu)體中的數(shù)組可以復(fù)制
5. 參數(shù)傳遞和返回值
五、總結(jié)
一、前言
在 C/C++ 語(yǔ)言中,數(shù)組類型的變量是不可以直接賦值的。但是如果把數(shù)組放在結(jié)構(gòu)體中,然后對(duì)結(jié)構(gòu)體變量進(jìn)行賦值,就可以實(shí)現(xiàn)把其中的數(shù)組內(nèi)容進(jìn)行復(fù)制過(guò)去。
很多朋友對(duì)這個(gè)不是特別理解,只是強(qiáng)制記憶,下面我嘗試用自己的理解來(lái)描述一下,希望對(duì)你有所幫助!
二、數(shù)組的各種操作
1. 錯(cuò)誤代碼int a[5] = {1, 2, 3, 4, 5};
int b[5];
b = a;
對(duì)于上面的賦值語(yǔ)句,編譯器會(huì)報(bào)錯(cuò) error: assignment to expression with array type,即:不能對(duì)一個(gè)數(shù)組類型的變量進(jìn)行賦值。
那么編譯器此時(shí)是如何來(lái)解釋 a 和 b 的?下面會(huì)說(shuō)到這個(gè)問(wèn)題。
有一個(gè)地方提一下:第一條語(yǔ)句中的 = 操作,不是賦值,而是初始化。C/C++ 語(yǔ)法規(guī)定在定義變量的時(shí)候,是可以使用 操作符 = 來(lái)進(jìn)行初始化操作的。
2. 利用結(jié)構(gòu)體來(lái)復(fù)制數(shù)組typedef struct {
int arr[5];
} array_wrap;
array_wrap a = {{1, 2, 3, 4, 5}};
array_wrap b;
b = a;
這里的賦值操作是針對(duì)結(jié)構(gòu)體變量,C 語(yǔ)言標(biāo)準(zhǔn)允許這種行為,是合法的,變量 a 中的所有內(nèi)容(也就是這個(gè)變量占用過(guò)的那一塊內(nèi)存空間中的內(nèi)容)會(huì)原樣的復(fù)制到變量 b 中。
3. 其他復(fù)制方式
既然不能直接對(duì)數(shù)組類型的變量進(jìn)行賦值,只能尋求其他的替代方式,例如:
利用 memcpy(b, a, sizeof(int) * 5); 復(fù)制一整段內(nèi)存空間中的內(nèi)容;利用 for/while 等循環(huán)語(yǔ)句,逐個(gè)復(fù)制數(shù)組中每一個(gè)元素: b[i] = a[i];
三、語(yǔ)言標(biāo)準(zhǔn)和編譯器
C/C++ 只是一門(mén)高級(jí)語(yǔ)言,是被標(biāo)準(zhǔn)委員會(huì)從無(wú)到有設(shè)計(jì)出來(lái)的,因此我們編程時(shí)需要嚴(yán)格遵守這些規(guī)則。
這些規(guī)則中,就包括這么一條:只有標(biāo)量和結(jié)構(gòu)體,才能出現(xiàn)在賦值操作符=的左側(cè)。
但是數(shù)組類型并不是一個(gè)標(biāo)量,因此不能對(duì)結(jié)構(gòu)體執(zhí)行賦值操作。
理論上,如果 C/C++ 語(yǔ)言愿意的話,是"可以"對(duì)數(shù)組直接賦值的(那就要修改語(yǔ)法標(biāo)準(zhǔn)),只不過(guò)標(biāo)準(zhǔn)委員會(huì)在經(jīng)過(guò)各種場(chǎng)景的權(quán)衡利弊之后,做出了目前這樣的規(guī)定,這是對(duì)各種考慮到的因素進(jìn)行權(quán)衡之后的結(jié)果。
也就是說(shuō),目前標(biāo)準(zhǔn)中對(duì)于數(shù)組操作的方式,是利大于弊。
既然標(biāo)準(zhǔn)已經(jīng)是制定成這樣的了,我們就來(lái)分析一下編譯器是如何來(lái)遵循、實(shí)現(xiàn)這個(gè)標(biāo)準(zhǔn)的。
1. 數(shù)組與指針的曖昧關(guān)系
很多人都這樣記憶:數(shù)組名就是數(shù)組開(kāi)始地址的指針。這是不對(duì)的,或者說(shuō)不嚴(yán)謹(jǐn)?shù)摹?/p>
在 C/C++ 中,數(shù)組就是數(shù)組,指針就是指針。數(shù)組在內(nèi)存中有確定的空間(每個(gè)元素的大小 x 元素個(gè)數(shù))。
只不過(guò)在表達(dá)式中,數(shù)組名會(huì)“臨時(shí)的”表示數(shù)組中第一個(gè)元素的常量指針(前提條件:在沒(méi)有操作符 sizeof 和 & 的情況下)。
對(duì)于下面這段代碼,打印結(jié)果是相同的:
int a[5] = {1, 2, 3, 4, 5};
printf("a = %p ", a);
printf("&a = %p ", &a);
第一個(gè) printf 中,a 會(huì)“臨時(shí)的”代表指向第一個(gè)元素的常量指針。
第二個(gè) printf 中,a 就表示一個(gè)數(shù)組,與指針沒(méi)有半毛錢(qián)的關(guān)系,前面加上取地址符 &,就表示獲取這個(gè)數(shù)組所在的地址,這個(gè)地址與第一個(gè)元素的地址是重合的。
注意:代碼在被編譯成二進(jìn)制文件之后,沒(méi)有任何變量的概念,全部是用地址來(lái)“傳遞” C/C++ 代碼中的變量。
2. 為什么不能對(duì)數(shù)組變量賦值
有了上面的基礎(chǔ)理解就好辦了,對(duì)于下面的這段代碼:
int a[5] = {1, 2, 3, 4, 5};
int b[5];
b = a;
在賦值語(yǔ)句 b = a 中,左側(cè)的 b 是一個(gè)數(shù)組類型,右側(cè)的 a 被編譯器“臨時(shí)的”代表第一個(gè)元素的常量指針,但是數(shù)組不是一個(gè)標(biāo)量,不可以放在賦值運(yùn)算符=的左側(cè),因此編譯器就抱怨:非法!
既然在一個(gè)表達(dá)式中,數(shù)組名被臨時(shí)的表示第一個(gè)元素的常量指針,那么就說(shuō)明我們不能對(duì)數(shù)組名本身進(jìn)行計(jì)算,例如:不能進(jìn)行 a++, a-- 等操作。
例如:下面這的遍歷方式是非法的:
int a[5] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++)
{
// 常量指針,不可以進(jìn)行遞增操作
printf("a[%d] = %d ", i, *a++);
}
3. 函數(shù)形參是數(shù)組的情況
考慮下面這個(gè)函數(shù):
void func(int arr[5])
{
for (int i = 0; i < 5; ++i)
{
printf(*arr++); // 合法!
}
}
形參 arr 在形式上好像是一個(gè)數(shù)組,實(shí)際上被編譯器當(dāng)做指針,也就是相當(dāng)于:void func(int *arr),因此,在 printf 打印語(yǔ)句中,可以對(duì) arr 進(jìn)行遞增操作。
PS: 這種場(chǎng)景下都需要額外的傳遞一個(gè)參數(shù),來(lái)告知元素的個(gè)數(shù)。
調(diào)用這個(gè)函數(shù)的代碼如下:
int a[5] = {1, 2, 3, 4, 5};
fun(a);
數(shù)組名臨時(shí)代表第一個(gè)元素的常量指針,在傳參的時(shí)候,形參 arr 的值就是數(shù)組中第一個(gè)元素的內(nèi)存地址。
4. 為什么結(jié)構(gòu)體中的數(shù)組可以復(fù)制
有了前面的語(yǔ)法標(biāo)準(zhǔn),這個(gè)問(wèn)題似乎不用再討論了~~
賦值的目的是什么?就是讓一塊內(nèi)存空間的內(nèi)容,與另一塊內(nèi)存空間中的內(nèi)容完全相同。如果想要完成復(fù)制操作,那么就需要知道這塊內(nèi)存空間的大小。
編譯器是知道一個(gè)結(jié)構(gòu)體變量所占用的空間大小的,所以當(dāng)復(fù)制的時(shí)候,類似于 memcpy 一樣,把一個(gè)結(jié)構(gòu)體變量所占空間按照 byte to byte 的方式復(fù)制過(guò)去。
5. 參數(shù)傳遞和返回值在調(diào)用函數(shù)時(shí),實(shí)參到形參的傳遞;函數(shù)執(zhí)行結(jié)束后的返回值;
這兩個(gè)場(chǎng)景中都涉及到變量的賦值問(wèn)題。
關(guān)于參數(shù)傳遞,上面已經(jīng)說(shuō)了:編譯器是把形參當(dāng)做普通的指針類型的。
對(duì)于函數(shù)返回值來(lái)說(shuō),同樣的道理,也不能直接返回一個(gè)數(shù)組,因?yàn)樗鼉H僅是臨時(shí)性的代表第一個(gè)元素的常量指針。
當(dāng)然,可以利用結(jié)構(gòu)體的可賦值特性,把數(shù)組包裹在其中,以此達(dá)到復(fù)制的效果。
五、總結(jié)
記住這兩句話:
1.?dāng)?shù)組就是數(shù)組,指針就是指針,它們各不相干。
2.在表達(dá)式中,數(shù)組名會(huì)“臨時(shí)的”表示數(shù)組中第一個(gè)元素的常量指針(前提條件:在沒(méi)有操作符 sizeof 和 & 的情況下)

發(fā)表評(píng)論
請(qǐng)輸入評(píng)論內(nèi)容...
請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字
最新活動(dòng)更多
-
3月27日立即報(bào)名>> 【工程師系列】汽車電子技術(shù)在線大會(huì)
-
4月30日立即下載>> 【村田汽車】汽車E/E架構(gòu)革新中,新智能座艙挑戰(zhàn)的解決方案
-
5月15-17日立即預(yù)約>> 【線下巡回】2025年STM32峰會(huì)
-
即日-5.15立即報(bào)名>>> 【在線會(huì)議】安森美Hyperlux™ ID系列引領(lǐng)iToF技術(shù)革新
-
5月15日立即下載>> 【白皮書(shū)】精確和高效地表征3000V/20A功率器件應(yīng)用指南
-
5月16日立即參評(píng) >> 【評(píng)選啟動(dòng)】維科杯·OFweek 2025(第十屆)人工智能行業(yè)年度評(píng)選
推薦專題
- 1 UALink規(guī)范發(fā)布:挑戰(zhàn)英偉達(dá)AI統(tǒng)治的開(kāi)始
- 2 北電數(shù)智主辦酒仙橋論壇,探索AI產(chǎn)業(yè)發(fā)展新路徑
- 3 降薪、加班、裁員三重暴擊,“AI四小龍”已折戟兩家
- 4 “AI寒武紀(jì)”爆發(fā)至今,五類新物種登上歷史舞臺(tái)
- 5 國(guó)產(chǎn)智駕迎戰(zhàn)特斯拉FSD,AI含量差幾何?
- 6 光計(jì)算迎來(lái)商業(yè)化突破,但落地仍需時(shí)間
- 7 東陽(yáng)光:2024年扭虧、一季度凈利大增,液冷疊加具身智能打開(kāi)成長(zhǎng)空間
- 8 地平線自動(dòng)駕駛方案解讀
- 9 封殺AI“照騙”,“淘寶們”終于不忍了?
- 10 優(yōu)必選:營(yíng)收大增主靠小件,虧損繼續(xù)又逢關(guān)稅,能否乘機(jī)器人東風(fēng)翻身?