C語(yǔ)言基本結(jié)構(gòu)(下)
Every program is a part of some other program and rarely fits.[0]
碼字不易疫鹊,對(duì)你有幫助 點(diǎn)贊/轉(zhuǎn)發(fā)/關(guān)注 支持一下作者
微信搜公眾號(hào):不會(huì)編程的程序圓
看更多干貨舵抹,獲取第一時(shí)間更新
推薦在我的公眾號(hào)上閱讀柑土,排版比較好,點(diǎn)擊查看:
思維導(dǎo)圖
寫(xiě)在前面
如果只是寫(xiě)個(gè)人學(xué)習(xí)總結(jié)的博客很容易,簡(jiǎn)單寫(xiě)一些感悟然后貼上代碼走人就可以了,甚至不用校審千扶。但是我命名本系列為【C語(yǔ)言必知必會(huì)】幫助你從入門(mén)到精通 C語(yǔ)言,那勢(shì)必要“事無(wú)巨細(xì)”一些:既要考慮到?jīng)]有基礎(chǔ)的初學(xué)者骆捧,又不能止于基礎(chǔ)澎羞。所以本教程適合各類(lèi)人群學(xué)習(xí),只要你看就一定會(huì)有幫助敛苇。
本教程是本人純手打并排版妆绞,校審由我與我的搭檔湯圓君一起完成的。你們看這一篇文章我要寫(xiě)好幾個(gè)小時(shí)枫攀。如果文章對(duì)你有幫助括饶,請(qǐng)不要“白嫖”。支持一下作者脓豪,作者會(huì)發(fā)更多干貨好文巷帝。
特別鳴謝:湯圓君(公眾號(hào):【Cc聽(tīng)香水榭】 長(zhǎng)期更新高質(zhì)量英語(yǔ)教學(xué))關(guān)注她表示對(duì)她工作的認(rèn)可吧忌卤!
》 此符號(hào)表示該內(nèi)容以后的章節(jié)會(huì)講解扫夜,此章節(jié)內(nèi)不要求理解。
簡(jiǎn)單的程序結(jié)構(gòu)
下面是一個(gè)簡(jiǎn)單的程序,身高是給出的笤闯,體重是在程序中得到的堕阔,我們輸出的是體重與身高/體重的值。
這里我們更注重的是程序的結(jié)構(gòu)而非程序本身颗味。
示例
<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;">在這里插入圖片描述</figcaption>
1. 類(lèi)型
每一個(gè)變量都有類(lèi)型(type)超陆。類(lèi)型用來(lái)描述變量的數(shù)據(jù)的種類(lèi)仓蛆,也稱(chēng)數(shù)據(jù)類(lèi)型陷舅。
數(shù)值型變量的類(lèi)型決定了變量所能存儲(chǔ)的最大值與最小值彼绷,以及是否允許小數(shù)點(diǎn)后出現(xiàn)數(shù)字解幼。
示例中只有一種數(shù)據(jù)類(lèi)型:int
int(integer):即整型弥搞,表示整數(shù)炬守。
數(shù)據(jù)類(lèi)型還有很多洼哎,目前除了 int 以外呕屎,我們只再使用另一種:
float(floating-point): 浮點(diǎn)型磺陡,可以表示小數(shù)
注意:雖然 float 型可以帶小數(shù)趴梢,但是進(jìn)行算術(shù)運(yùn)算時(shí),float 型要比 int 型慢币他,而且 float 通常只是一個(gè)值的近似值坞靶。(比如在一個(gè)float 型變量中存儲(chǔ) 0.1, 但其實(shí)可能這個(gè)變量的值為 0.09999987蝴悉,這是舍入造成的誤差)
題外話(huà):我當(dāng)時(shí)學(xué)的時(shí)候彰阴,就沒(méi)有人告訴我這些知識(shí),你們?nèi)绻F(xiàn)在是初學(xué)辫封,我都感覺(jué)到羨慕硝枉,你們要少走多少?gòu)澛钒。?/em>
2. 關(guān)鍵字
int 與float 都是C語(yǔ)言的關(guān)鍵字(keyword),關(guān)鍵字是語(yǔ)言定義的單詞倦微,不能用做其他用途妻味。比如不能用作命名函數(shù)名與變量名。
關(guān)鍵字:斜體代表C99新增關(guān)鍵字
auto | enum | unsigned | break | extern |
---|---|---|---|---|
return | void | case | float | short |
volatile | char | for | signed | while |
const | goto | sizeof | continue | if |
static | default | struct | do | int |
switch | double | long | typedef | else |
register | union | |||
restrict | inline | _Bool | _Complex | _Imaginary |
如果關(guān)鍵字使用不當(dāng)(關(guān)鍵字作為變量名)欣福,編譯器會(huì)將其視為語(yǔ)法錯(cuò)誤责球。
保留標(biāo)識(shí)符(reserved identifier):下劃線(xiàn)開(kāi)頭的標(biāo)識(shí)符和標(biāo)準(zhǔn)庫(kù)函數(shù)名(如:printf())
C語(yǔ)言已經(jīng)指定了這些標(biāo)識(shí)符的用途或保留了它們的使用權(quán),如果你使用它們作為變量名拓劝,即使沒(méi)有語(yǔ)法錯(cuò)誤雏逾,也不能隨便使用。
3. 聲明
聲明(declaration):在使用變量(variable)之前郑临,必須對(duì)其進(jìn)行聲明(為編譯器所作的描述)栖博。
聲明的方式為:數(shù)據(jù)類(lèi)型 + 變量名(程序員自己決定變量名,命名規(guī)則后面會(huì)講)
示例中的 int weight
完成了兩件事情厢洞。第一仇让,函數(shù)中有個(gè)變量名為 weight典奉。第二,int 表明這個(gè)變量是整型丧叽。
編譯器用這些信息為變量 weight 在內(nèi)存中分配空間卫玖。
C99 前,如果有聲明踊淳,聲明一定要在語(yǔ)句之前假瞬。(就像示例那樣,函數(shù)體中第一塊是聲明迂尝,第二塊才是語(yǔ)句脱茉。)
C99 和 C11 遵循 C++ 的慣例,可以把聲明放在任何位置垄开。即可以使用時(shí)再聲明變量芦劣。以后C程序中這種做法可能會(huì)很流行。但是目前不建議這樣说榆。
就書(shū)寫(xiě)格式而言虚吟,我建議將聲明全部放在函數(shù)體頭部,聲明與語(yǔ)句之間空出一行签财。
4. 命名
weight,height 都是標(biāo)識(shí)符串慰,也就是一個(gè)變量,函數(shù)或其他實(shí)體的名稱(chēng)唱蒸。因此邦鲫,聲明將特定標(biāo)識(shí)符與計(jì)算機(jī)內(nèi)存的特定位置聯(lián)系起來(lái),同時(shí)也就確定了存儲(chǔ)在某位置的信息類(lèi)型或數(shù)據(jù)類(lèi)型神汹。
給變量命名時(shí)要使用有意義的變量名或標(biāo)識(shí)符庆捺。如果變量名無(wú)法清楚的表達(dá)自身的用途,可以在注釋中進(jìn)一步說(shuō)明屁魏,這是一種良好的編程習(xí)慣與編程技巧滔以。
C99 與 C11 允許使用更長(zhǎng)的標(biāo)識(shí)符,但是編譯器只識(shí)別前 63個(gè)字符氓拼。對(duì)于外部標(biāo)識(shí)符你画,只允許 31 個(gè)字符。事實(shí)上桃漾,你可以使用更長(zhǎng)的字符坏匪,但是編譯器可能忽略超出的部分。(比如有兩個(gè)標(biāo)識(shí)符都是 64 個(gè)字符撬统,但只有最后一個(gè)字符不同适滓。編譯器可能會(huì)視其為同一個(gè)名字,也可能不會(huì)恋追。標(biāo)準(zhǔn)并未定義在這種情況下會(huì)發(fā)生什么凭迹。)
命名規(guī)則:可以用小寫(xiě)字母颅崩,大寫(xiě)字母,數(shù)字和下劃線(xiàn)(_)來(lái)命名蕊苗。名稱(chēng)的第一個(gè)字符必須是字符或下劃線(xiàn),不能是數(shù)字
操作系統(tǒng)和C庫(kù)經(jīng)常使用一個(gè)下劃線(xiàn)或兩個(gè)下劃線(xiàn)開(kāi)始的標(biāo)識(shí)符(如:_kcab)沿彭,因此最好避免在自己的程序中使用這種名稱(chēng)朽砰。(避免與操作系統(tǒng)和c庫(kù)的標(biāo)識(shí)符重復(fù))
C語(yǔ)言的名稱(chēng)區(qū)分大小寫(xiě)。即:star喉刘,Star瞧柔,STAR 是不同的。
聲明變量的理由:
- 把所有變量放在一處睦裳,方便讀者查找和理解程序的用途造锅。
- 聲明變量可以促使你在編寫(xiě)程序之前做好計(jì)劃(比如你的程序要用什么變量,你可以提前規(guī)劃)廉邑。
- 聲明變量有助于發(fā)現(xiàn)程序中的小錯(cuò)誤哥蔚,如拼寫(xiě)錯(cuò)誤。
- 不提前聲明變量蛛蒙,C程序編譯將無(wú)法通過(guò)
5. 賦值
賦值(assignment):變量通過(guò)賦值的方式獲得值糙箍。
示例中,weight = 160;
是一個(gè) 賦值表達(dá)式語(yǔ)句牵祟。意思是“把值 160 賦給 變量 weight”深夯。
在執(zhí)行 int weight;
時(shí),編譯器在計(jì)算機(jī)內(nèi)存中為變量 weight 預(yù)留的空間诺苹,然后在執(zhí)行這行代碼時(shí)咕晋,把值存儲(chǔ)在之前預(yù)留的位置∈毡迹可以給 weight 賦不同的值掌呜,這就是 weight 之所以被稱(chēng)為變量的原因。
注意:
該行表達(dá)式將值從右側(cè)賦到左側(cè)坪哄。
該語(yǔ)句以分號(hào)結(jié)尾站辉。
=
在計(jì)算機(jī)中不是相等的意思,而是賦值损姜。我們?cè)谧xweight = 160;
時(shí)饰剥,我們應(yīng)該這么讀:“將 160 賦給 weight”==
表示相等
6. printf() 函數(shù)
printf(“我的體重是:%d斤\n,身高與體重的比為:%d”, weight, height / weight);
這是我們示例中的 printf 函數(shù)摧阅,我們來(lái)看兩個(gè)不那么復(fù)雜的:
main(void);printf("Hi");
首先汰蓉,printf() 的 圓括號(hào)是不是很像 main() ?這表示 printf 是一個(gè)函數(shù)名棒卷,它也是一個(gè)函數(shù)顾孽。圓括號(hào)內(nèi)的內(nèi)容是從 main() 函數(shù)傳遞給 printf() 函數(shù)的信息祝钢。該信息被稱(chēng)為參數(shù),更確切的說(shuō)若厚,是實(shí)際參數(shù)(actual argument)拦英,簡(jiǎn)稱(chēng)實(shí)參。
既然是函數(shù)测秸,它其實(shí)也是像我們看到的 main函數(shù)一樣疤估,也有函數(shù)頭和函數(shù)體。
printf() 函數(shù)是一個(gè)庫(kù)函數(shù)霎冯,庫(kù)函數(shù)我們上一節(jié)講函數(shù)種類(lèi)時(shí)說(shuō)過(guò)铃拇,這是一種不需要程序員去寫(xiě)的,只需要引用頭文件 stdio.h
就可以直接使用的沈撞。但是我們應(yīng)該知道這一點(diǎn)慷荔,詳細(xì)情況我們后面會(huì)說(shuō)講。
當(dāng)程序運(yùn)行到 printf() 函數(shù)這一行時(shí)缠俺,控制權(quán)被轉(zhuǎn)給了printf()函數(shù)显晶。函數(shù)執(zhí)行結(jié)束后,控制權(quán)被返回至主調(diào)函數(shù)(calling function)壹士,該例中是 main() 吧碾。
printf() 函數(shù)的作用是向我們的顯示器輸出內(nèi)容。
此例中墓卦,printf() 函數(shù)的括號(hào)內(nèi) 分為兩部分倦春,一部分在雙引號(hào)內(nèi),另一部分在雙引號(hào)外落剪,它們中間以逗號(hào)隔開(kāi)睁本。雙引號(hào)外有兩個(gè)參數(shù) weight 和 height / weight ,他們分別是變量和表達(dá)式(含有常量忠怖,變量和運(yùn)算符的式子)呢堰,也是指定要被打印的參數(shù)(打印到你的屏幕上)。
我們發(fā)現(xiàn)凡泣,最終我們屏幕上看到的是引號(hào)內(nèi)的內(nèi)容枉疼。我們可以來(lái)看一下輸出的內(nèi)容:
我的體重是:160斤身高與體重的比為:1
我們發(fā)現(xiàn):首先引號(hào)內(nèi)的 %d
和\n
并沒(méi)有被輸出,%d
的位置被替換成了一個(gè)整數(shù)鞋拟。為什么會(huì)這樣呢骂维?
\n
代表一個(gè)換行符(newline character)。對(duì)于 printf 函數(shù)來(lái)說(shuō)贺纲,它的意思是:“在下一行的最左邊開(kāi)始新的一行”航闺。也就是說(shuō)換行符和在鍵盤(pán)上按下 Enter按鍵相同。既然如此,為何不在鍵入 printf() 參數(shù)時(shí)直接使用 Enter鍵呢潦刃?因?yàn)榫庉嬈骺赡苷J(rèn)為這是直接的命令侮措,而不是存儲(chǔ)在源代碼中的指令。換句話(huà)說(shuō)乖杠,如果直接按下 Enter鍵分扎,編輯器會(huì)退出當(dāng)前行并開(kāi)始新的一行。但是胧洒,換行符會(huì)影響程序輸出的(顯示)格式畏吓。
換行符是一個(gè)轉(zhuǎn)義序列(escape sequence)。轉(zhuǎn)義序列用于難以表示或無(wú)法輸入的字符略荡。如,\t
代表 Tab鍵,即制表符歉胶。\b
代表 Backspace鍵汛兜,即退格鍵。我們?cè)诤竺鏁?huì)繼續(xù)討論通今。
這樣就解釋了為何一行的printf() 函數(shù)會(huì)輸出兩行粥谬。
以下這部分不能理解可以只看結(jié)論,能理解更好辫塌。
在解釋 %d 之前我們先來(lái)看一下漏策,weight 和 height / weight 所代表的值。
weight 是被賦值為 160 的臼氨,所以 weight 的值就是 160
C語(yǔ)言中掺喻,/
表示除法, *
表示乘法储矩。
那么 height / weight 的值是多少呢感耙?我們現(xiàn)在不知道這個(gè)表達(dá)式的值是多少,但是我們知道這個(gè)它肯定代表 180 / 160
而最終輸出的值是 1 持隧,這和我們想的不一樣即硼,我們知道結(jié)果應(yīng)該是個(gè)小數(shù),那么這是為什么呢屡拨?
我想可能的原因有兩個(gè):
- %d 將小數(shù)轉(zhuǎn)換為整數(shù)
- 180 / 160 本身在C語(yǔ)言中的值就是整數(shù)
我們來(lái)測(cè)試一下:
int main(void) { int a = 3; int b = 2; float c = 1.1f;//f 表示1.1是浮點(diǎn)數(shù) printf("%d\n", c);//%d 用來(lái)輸出整型 printf("%f\n", a / b);//%f 用來(lái)輸出浮點(diǎn)型 return 0;}
輸出:
-17179869180.000000
輸出并不是我們想要的內(nèi)容只酥,我們來(lái)看一下編譯器的警告:
編譯器警告:
“printf”: 格式字符串“%d”需要類(lèi)型“int”的參數(shù),但可變參數(shù) 1 擁有了類(lèi)型“double” “printf”: 格式字符串“%f”需要類(lèi)型“double”的參數(shù)呀狼,但可變參數(shù) 1 擁有了類(lèi)型“int”
可以不去理解報(bào)錯(cuò)的內(nèi)容裂允。輸出與報(bào)錯(cuò)至少說(shuō)明了一點(diǎn):
%d 在我的編譯器上無(wú)法輸出浮點(diǎn)型;整型 / 整型 不是浮點(diǎn)型哥艇。
那就說(shuō)明了原因2是對(duì)的叫胖,即:180 / 160 的值就是 1
為什么 180 / 160 == 1
(180 / 160 的值是 1)呢?
因?yàn)?weight 和 height 都整數(shù)她奥,它們相除結(jié)果取整數(shù)(向下取整)瓮增。
如何輸出 float 類(lèi)型的浮點(diǎn)數(shù)怎棱?
printf("%f", 2.0f);
%d
是一個(gè)占位符,其作用是指明 num 值的位置绷跑。d 代表 以十進(jìn)制的格式拳恋。
還有一點(diǎn)要注意的是,在示例中砸捏,第二個(gè)輸出的整數(shù)的參數(shù)(height / weight )是一個(gè)表達(dá)式谬运,我們也可以在程序中添加一個(gè)新的變量,然后用這個(gè)變量代替上面的表達(dá)式作為 printf() 的參數(shù)垦藏。如:
int main(void){ int height = 180; int weight, scale;//scale:比例 weight = 160; scale = height / weight; printf(“我的體重是:%d斤\n梆暖,身高與體重的比為:%d”, weight, scale); return 0;}
合理的使用表達(dá)式作為函數(shù)的參數(shù)可以簡(jiǎn)化程序。
也說(shuō)明在任何需要數(shù)值的地方掂骏,都可以使用具有相同類(lèi)型的表達(dá)式轰驳。
7. 初始化
當(dāng)程序開(kāi)始執(zhí)行時(shí),某些變量會(huì)被自動(dòng)設(shè)置為0弟灼,而大多數(shù)不會(huì)级解。沒(méi)有默認(rèn)值并且尚未在程序中被賦值的變量時(shí)未初始化的(uninitialized)。
如果試圖訪(fǎng)問(wèn)未初始化的變量田绑,可能會(huì)得到不可預(yù)知的值勤哗。在某些編譯器中,可能會(huì)發(fā)生更壞的情況(甚至程序崩潰)掩驱。
我們可以用賦值的辦法給變量賦初值芒划,但還有更簡(jiǎn)潔的做法:在變量聲明中加入初始值。
例如示例中的 int height = 180
數(shù)值 180 就是一個(gè)初始化式(initializer)欧穴。
同一個(gè)聲明中可以對(duì)任意數(shù)量的變量進(jìn)行初始化腊状。如:
int a = 10, b = 15, c = 20;
上述每個(gè)變量都擁有屬于自己的初始化式。接下來(lái)的例子苔可,只有 c 有初始化式缴挖,a,b沒(méi)有焚辅。
int a, b, c = 20;
<small class="footnote" id="footnote-0" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px;">[0]: 每個(gè)程序都是其他程序不合適的一部分映屋。</small>
參考資料:《C Primer Plus》《C語(yǔ)言程序設(shè)計(jì):現(xiàn)代方法》
本文GitHub已更新,所有教學(xué)和練習(xí)代碼都會(huì)上傳上去同蜻,歡迎 star 棚点!
以上就是本次的內(nèi)容。
如果文章有錯(cuò)誤歡迎指正和補(bǔ)充湾蔓,感謝瘫析!
最后,如果你還有什么問(wèn)題或者想知道到的,可以在評(píng)論區(qū)告訴我呦贬循,我可以在后面的文章加上你們的真知灼見(jiàn)咸包。
關(guān)注我,看更多干貨杖虾!
我是程序圓烂瘫,我們下次再見(jiàn)。