C 語(yǔ)言基礎(chǔ)教程(我的C之旅開(kāi)始了)[十]
27. 表達(dá)式(Expression)
表達(dá)式由運(yùn)算符和操作數(shù)組成。單獨(dú)一個(gè)操作數(shù)是最簡(jiǎn)單的表達(dá)式。請(qǐng)看以下例子:
9
-4
+5
3 + 6
a * ( b/c - d )
e = 9 / 3
f = ++e % 3
表達(dá)式中的表達(dá)式稱為子表達(dá)式。例如:b/c 是 a * ( b/c - d ) 的子表達(dá)式。
每個(gè)表達(dá)式都有一個(gè)值,這是 C 語(yǔ)言的一個(gè)重要屬性。顯而易見(jiàn)的,9 和 -4 的值就是 9 和 -4,3 + 6 的值就是 9 。e = 9 / 3 的值是 3 ,也就是是 = 號(hào)左邊的變量 e 被賦予的值。我們?cè)賮?lái)看看下面這個(gè)表達(dá)式:
8 - (a = 2 * 3)
想想看,它的值是多少?沒(méi)錯(cuò),就是 2 。但是,不推薦使用這種表達(dá)式,因?yàn)榭勺x性太差。
| 28. 數(shù)組基礎(chǔ)(上) |
|
1. 數(shù)組簡(jiǎn)介 數(shù)組(Array)由一系列同種數(shù)據(jù)類型的元素組成。編譯器可以從數(shù)組聲明中知道數(shù)組中元素的數(shù)目,以及這些元素的數(shù)據(jù)類型。例如: double dbl[20]; /* 包含 20 個(gè) double 類型元素的數(shù)組 */ 方括號(hào) [] 表明它們是數(shù)組,[] 里的數(shù)字表明數(shù)組包含的元素?cái)?shù)目。 數(shù)組中的元素是相鄰的,初始化之前,元素的值可能是隨機(jī)的。下圖形象地表現(xiàn)了這種相鄰關(guān)系。 使用數(shù)組名和下標(biāo)(subscript number 或 index)就可以訪問(wèn)特定的元素。下標(biāo)始于 0,止于 n - 1。例如:c[0] 是數(shù)組 c 的第一個(gè)元素,而 c[11] 是它的最后一個(gè)元素,也就是第 12 個(gè)元素。
int c[12] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; 如上所示,我們使用大括號(hào)中一系列逗號(hào)分隔的值來(lái)初始化數(shù)組。我們把這個(gè)稱之為初始化列表。大括號(hào)是必須的!逗號(hào)和值之間的空格可有可無(wú)。初始化后,數(shù)組 c 的第一個(gè)元素 c[0] 的值為 0,以此類推。 下面的小程序輸出數(shù)組 iarr 中所有元素的值。 #include <stdio.h> int main(void) printf("%d\n", iarr[0]); /* 輸出 0 */ return 0; 如上所示,訪問(wèn)數(shù)組元素時(shí),[] 里的可以是常量,可以是變量,也可以是表達(dá)式。[] 里還可以是返回值為整型的函數(shù)調(diào)用??傊?,只要 [] 里的值是整數(shù)類型都可以。 注意,上面的程序,如果把 int iarr[4] = { 0, 1, 2, 3 }; 改成 int iarr[4];(即沒(méi)有初始化),則它里面的元素的值是隨機(jī)的,也就是本來(lái)就存在于那段內(nèi)存空間的值。如果改成 int iarr[4]; 后再把它放在 int main(void) 之前,則它里面的元素的值都是 0。具體原因我在后續(xù)的教程會(huì)說(shuō)明。 如果初始化列表中的值的個(gè)數(shù)少于數(shù)組元素個(gè)數(shù),則余下的元素都會(huì)被初始化為 0。例如: int iarr[4] = { 0, 1 }; iarr[0] 和 iarr[1] 分別為 0 和 1;iarr[2] 和 iarr[3] 都被初始化為 0。注意,初始化列表中的值的個(gè)數(shù)可以少于數(shù)組元素個(gè)數(shù),但是超過(guò)數(shù)組元素個(gè)數(shù)卻是不對(duì)的! 初始化數(shù)組時(shí),[] 里可以留空。例如: int iarr[] = { 1, 2, 3 }; 編譯器會(huì)算出初始化列表中的值的個(gè)數(shù),然后構(gòu)造包含那么多個(gè)元素的數(shù)組。如上例,編譯器會(huì)算出列表中一共有 3 個(gè)值,然后把 iarr 構(gòu)造成包含 3 個(gè)元素的數(shù)組。例如: #include <stdio.h> int main(void) printf("%d\n", iarr[0]); /* 輸出 1 */ return 0; 我們可以用以下表達(dá)式算出 iarr 中元素的個(gè)數(shù): sizeof iarr / sizeof iarr[0] 其中,sizeof iarr 算出數(shù)組 iarr 占用的內(nèi)存大小,sizeof iarr[0] 算出 iarr[0] 占用的內(nèi)存大小(也就是數(shù)組 iarr 中每個(gè)元素占用的內(nèi)存大?。?,它們相除就得出 iarr 的元素個(gè)數(shù)。sizeof 是一個(gè)運(yùn)算符,具體用法我以后會(huì)說(shuō)。 |
| 29. 數(shù)組基礎(chǔ)(下) |
|
1. 指派初始值(Designated Initializers) 指派初始值這個(gè)特性是 C99 增加的,它允許我們直接初始化數(shù)組中特定的元素。C99 以前,如果我們要初始化數(shù)組中的某個(gè)元素,如第三個(gè)元素,必須同時(shí)初始化它之前的元素。例如: int iarr[10] = { 0, 0, 300 }; 而 C99 中,我們可以這樣初始化特定的元素: int iarr[10] = { [2] = 300 }; /* 指派初始化 iarr[2] 為 300 */ 其余的元素都會(huì)被初始化為 0 。下面我們來(lái)看一個(gè)小程序。 #include <stdio.h> int main(void) return 0; 輸出為: 6 從中可以看出兩點(diǎn): A. 如果指派初始值后面還有值,則后面的值會(huì)被用于初始化后續(xù)的元素。上例中, B. 如果初始化列表中多次出現(xiàn)對(duì)某元素的初始化,則以最后一次為準(zhǔn)。上例中,
我們可以利用下標(biāo)給特定的元素賦值。例如: int iarr[5]; C 不允許直接使用數(shù)組對(duì)別的數(shù)組進(jìn)行賦值,也不允許使用初始化列表對(duì)數(shù)組進(jìn)行賦值。例如: int iarr_1[5] = { 1, 2, 3, 4, 5 }; /* 正確 */ iarr_2 = iarr_1; /* 錯(cuò)誤! */ 最后一個(gè)語(yǔ)句發(fā)生了越界!因?yàn)檫@兩個(gè)數(shù)組都只有 5 個(gè)元素,而使用下標(biāo) 5 訪問(wèn)的是第六個(gè)元素!
3. 數(shù)組界限(array bounds) 使用下標(biāo)時(shí),我們必須確保下標(biāo)沒(méi)有越界。例如: int iarr[46]; 這個(gè)數(shù)組的下標(biāo)范圍是 0 到 45,確保下標(biāo)沒(méi)有超出這個(gè)范圍是我們的責(zé)任,因?yàn)榫幾g器不會(huì)對(duì)下標(biāo)越界進(jìn)行檢測(cè)! C 標(biāo)準(zhǔn)沒(méi)有定義下標(biāo)越界的后果,也就是說(shuō),當(dāng)我們寫的程序中出現(xiàn)下標(biāo)越界的問(wèn)題,程序可能正常工作,也可能異常退出,還有可能出現(xiàn)其它奇怪的情況。 #include <stdio.h> int main(void) printf("var_1: %d, var_2: %d\n", var_1, var_2); arr[-1] = -1; printf("%d %d\n", arr[-1], arr[5]); return 0; 上述程序使用 Dev-C++ 4.9.9.2 編譯運(yùn)行的輸出為: var_1: 20, var_2: 40 可見(jiàn),下標(biāo)越界可能改變其它變量的值。這是因?yàn)?gcc(dev-c++ 使用的 C 編譯器)把 var_2 保存于數(shù)組 arr 之前的內(nèi)存空間,所以對(duì) arr[-1] 賦值正好改變了 var_2 的值。不同的編譯器編譯運(yùn)行該程序可能會(huì)有不同的輸出,也可能會(huì)異常退出。 C 語(yǔ)言的哲學(xué)是信任程序員,而且不檢測(cè)越界程序運(yùn)行更快。程序編譯時(shí)有些下標(biāo)的值仍然是不可知的,所以如果要檢測(cè)下標(biāo)越界的話,編譯器必須在生成的目標(biāo)代碼中加入額外的代碼用于程序運(yùn)行時(shí)檢測(cè)下標(biāo)是否越界,這就會(huì)導(dǎo)致程序運(yùn)行速度下降。故而,為了運(yùn)行效率,C 不檢測(cè)下標(biāo)是否越界。
C99 之前,聲明數(shù)組時(shí),[] 中的值必須是大于零的整數(shù)常量。C99 中,聲明數(shù)組時(shí),[] 中可以是變量。這就是所謂的變長(zhǎng)數(shù)組(variable-length array,簡(jiǎn)稱 VLA)。聲明 VLA 時(shí),不能對(duì)其進(jìn)行初始化。在后續(xù)的教程中,我會(huì)對(duì) VLA 進(jìn)行詳細(xì)講解。 int n = 99; |
相關(guān)文章
Qt無(wú)邊框窗口拖拽和陰影的實(shí)現(xiàn)
自定義窗口控件的無(wú)邊框,窗口事件由于沒(méi)有系統(tǒng)自帶邊框,無(wú)法實(shí)現(xiàn)拖拽拉伸等事件的處理,本文主要介紹了Qt無(wú)邊框窗口拖拽和陰影的實(shí)現(xiàn),感興趣的可以了解一下2024-01-01
C++?Qt開(kāi)發(fā)之關(guān)聯(lián)容器類使用方法詳解
當(dāng)我們談?wù)摼幊讨械臄?shù)據(jù)結(jié)構(gòu)時(shí),順序容器是不可忽視的一個(gè)重要概念,Qt?中提供了豐富的容器類,用于方便地管理和操作數(shù)據(jù),本章我們將主要學(xué)習(xí)關(guān)聯(lián)容器,主要包括?QMap?,QSet和?QHash,感興趣的朋友跟著小編一起來(lái)學(xué)習(xí)吧2023-12-12
C++實(shí)現(xiàn)讀取特定路徑下文件夾及文件名的方法
這篇文章主要介紹了C++實(shí)現(xiàn)讀取特定路徑下文件夾及文件名的方法,需要的朋友可以參考下2014-07-07
超詳細(xì)解析C++實(shí)現(xiàn)快速排序算法的方法
快速排序是比較快的排序方法。它的基本思想是通過(guò)一組排序?qū)⒁判虻臄?shù)據(jù)分割成獨(dú)立的兩部分,本文將用C++實(shí)現(xiàn)快速排序算法,需要的可以參考一下2022-09-09
聊聊Qt+OpenCV聯(lián)合開(kāi)發(fā)之圖像的創(chuàng)建與賦值問(wèn)題
這篇文章主要介紹了Qt+OpenCV聯(lián)合開(kāi)發(fā)之圖像的創(chuàng)建與賦值問(wèn)題,給大家介紹了圖像的克隆及拷貝問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-01-01
C/C++程序開(kāi)發(fā)中實(shí)現(xiàn)信息隱藏的三種類型
這篇文章主要介紹了C/C++程序開(kāi)發(fā)中實(shí)現(xiàn)信息隱藏的三種類型的相關(guān)資料,需要的朋友可以參考下2016-02-02
C++ Strassen算法代碼的實(shí)現(xiàn)
這篇文章主要介紹了C++ Strassen算法代碼的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03


