# 一、C語(yǔ)言自我摸索之路
????????我是一名自動(dòng)化的本科生捂贿,研究生也是學(xué)的控制科學(xué)與工程纠修,因?yàn)樵谧詣?dòng)控制領(lǐng)域很多東西都是涉及的底層的控制,與硬件打交道比較多厂僧,所以學(xué)習(xí)的都是C語(yǔ)言扣草。
## 初識(shí)C語(yǔ)言
?????????首先就是和大家一樣,在大一就學(xué)習(xí)了C語(yǔ)言颜屠,C語(yǔ)言的基礎(chǔ)語(yǔ)法铆惑,如何編寫最基本的程序轩性,最后打印出來(lái)結(jié)果。在這個(gè)階段沒(méi)覺得C語(yǔ)言用來(lái)干嘛,有什么用亏娜,后來(lái)也就漸漸的忘記了拭宁。
##??偶遇C語(yǔ)言
?????????說(shuō)到偶遇聚假,真的完全是巧合碌廓,因?yàn)楫?dāng)時(shí)大三想要直接去實(shí)驗(yàn)室的,但是碰巧找的那個(gè)老師是做理論的背传,說(shuō)我還沒(méi)學(xué)習(xí)自動(dòng)控制的基礎(chǔ)理論呆瞻,還是先學(xué)學(xué)理論,大四在過(guò)來(lái)径玖。之后看到身邊同學(xué)報(bào)名了身邊的智能車比賽痴脾,自己和他就組隊(duì)參加了。所以直到大三參加了恩智浦智能車大賽(最后與國(guó)家一等獎(jiǎng)失之交臂梳星,作為大學(xué)的遺憾之一)赞赖,又重新拾起了C語(yǔ)言滚朵,這完全是一次巧合,但也正是這一次的偶遇前域,讓我與c語(yǔ)言結(jié)下了不解之緣辕近。在這個(gè)時(shí)候意識(shí)到了自己C語(yǔ)言的學(xué)習(xí)的欠缺,之前課程中的學(xué)習(xí)根本用處不大匿垄,只是認(rèn)識(shí)了基礎(chǔ)的語(yǔ)法移宅,但因?yàn)槟菚r(shí)候一方面比賽,一方面還要兼顧專業(yè)課的學(xué)習(xí)(當(dāng)然為了保研椿疗,哈哈哈)漏峰,所以還是秉承著夠用就好的原則,沒(méi)有過(guò)多追求C語(yǔ)言的知識(shí)會(huì)的有多深入届榄。
## 認(rèn)識(shí)C語(yǔ)言
?????????直到大三保研確定之后浅乔,我就徹底沒(méi)有了課業(yè)的壓力。于是開始了重新著手了C語(yǔ)言的深入學(xué)習(xí)之中痒蓬。也是不斷的在網(wǎng)上查找各種學(xué)習(xí)的套路啊,怎么入門啊滴劲,怎么提高之類的攻晒,我也是不斷的看書學(xué)習(xí)C語(yǔ)言,感覺自己還稍微入門了一點(diǎn)點(diǎn)班挖。也就真正的才剛剛認(rèn)識(shí)C語(yǔ)言鲁捏,之后就是暫時(shí)轉(zhuǎn)移到了數(shù)據(jù)結(jié)構(gòu)以及算法等其他計(jì)算機(jī)基礎(chǔ)知識(shí)的學(xué)習(xí),這些在之后的文章之中也會(huì)總結(jié)萧芙。
## 理解C語(yǔ)言????
????????C語(yǔ)言的另一次水平的提高给梅,就是在我準(zhǔn)備面試期間,準(zhǔn)備的工作崗位就是面向嵌入式軟件方面双揪,所以C語(yǔ)言是其中重要的一部分动羽,我又重新拾起了C語(yǔ)言的學(xué)習(xí)。在面經(jīng)和各個(gè)公司的面試題中查找自己在知識(shí)的盲區(qū)渔期,發(fā)現(xiàn)自己大四當(dāng)時(shí)自以為已經(jīng)真正學(xué)會(huì)了C語(yǔ)言還是一塌糊涂(學(xué)習(xí)還是得腳踏實(shí)地啊运吓,不能盲目自信),各種面試題根本不會(huì)疯趟,也就是開始按照面經(jīng)與筆試的常見考題不斷學(xué)習(xí)拘哨,不斷補(bǔ)足知識(shí)的盲區(qū)。當(dāng)然也是憑借自己的努力與運(yùn)氣信峻,先后拿到了中興倦青、海康盹舞、tplink产镐、vivo隘庄、華為以及一些研究所的offer。個(gè)人還是很滿意的磷账。
## 領(lǐng)悟C語(yǔ)言
????????在經(jīng)過(guò)面試的一系列考核之后峭沦,我就思考如何去總結(jié)C語(yǔ)言呢,C語(yǔ)言到底是學(xué)什么呢逃糟?什么樣才是學(xué)會(huì)C語(yǔ)言呢吼鱼?于是我又重新閱讀了之前的大四當(dāng)時(shí)閱讀的C語(yǔ)言的書,每讀一些绰咽,哎這不是C語(yǔ)言筆試面試彻剿啵考的嘛,這個(gè)也是啊取募。發(fā)現(xiàn)原來(lái)所有的知識(shí)書中都講了琐谤,只是那個(gè)時(shí)候?qū)W習(xí)沒(méi)有抓住重點(diǎn)。這個(gè)時(shí)候就覺得“參禪之初玩敏,看山是山斗忌,看水是水;禪有悟時(shí)旺聚,看山不是山织阳,看水不是水;禪中徹悟砰粹,看山仍是山唧躲,看水仍是水”也適合于C語(yǔ)言的學(xué)習(xí),初學(xué)之時(shí)C語(yǔ)言好簡(jiǎn)單啊碱璃,怎么樣弄痹,聽到很多人都說(shuō)我會(huì)C語(yǔ)言啊,本科學(xué)過(guò)扒镀鳌肛真;稍微深入學(xué)習(xí)一點(diǎn),哎呀好難啊爽航,指針好難盎傩馈;最后在大量的學(xué)習(xí)輸入之后領(lǐng)悟到C語(yǔ)言就是這些內(nèi)容岳掐。通過(guò)重新閱讀一遍之前學(xué)習(xí)的書籍凭疮,總結(jié)出了自己對(duì)于C語(yǔ)言學(xué)習(xí)之路的見解,所以想分享出來(lái)串述,希望可以為之后學(xué)習(xí)C語(yǔ)言提供些許幫助执解。
# 二、C語(yǔ)言知識(shí)結(jié)構(gòu)與難點(diǎn)解析
??????先來(lái)看看我總結(jié)的知識(shí)思維導(dǎo)圖
?????????當(dāng)你學(xué)C語(yǔ)言的時(shí)候,可能覺得好多內(nèi)容啊衰腌,但是當(dāng)你把基礎(chǔ)知識(shí)(這里不談編程水平)全部都學(xué)了新蟆,總是感覺好亂啊,知識(shí)很雜右蕊,那是因?yàn)槟銢](méi)有掌握結(jié)構(gòu)化思維琼稻,如果按照結(jié)構(gòu)化思維將C語(yǔ)言知識(shí)整理為如上圖所示的結(jié)構(gòu),就會(huì)立刻清晰起來(lái)饶囚,在把繁雜的知識(shí)點(diǎn)一點(diǎn)點(diǎn)細(xì)化到這個(gè)結(jié)構(gòu)中帕翻,你會(huì)發(fā)現(xiàn)原來(lái)C語(yǔ)言也沒(méi)有那么雜,還是很清晰的萝风,看山仍是山嘀掸,看水仍是水。
????????對(duì)于C語(yǔ)言基礎(chǔ)知識(shí)等問(wèn)題规惰,學(xué)習(xí)的路徑書籍在后面分享睬塌,這里先談?wù)勎覍?duì)于C語(yǔ)言中一些難點(diǎn)的一些思考與感悟。這部分最好在你學(xué)完之后在來(lái)體會(huì)一下歇万,最好也把你的體會(huì)也分享給我揩晴。
## C語(yǔ)言變量與指針的本質(zhì)?
?????????其實(shí)C語(yǔ)言最難理解的東西都說(shuō)是指針,不論是數(shù)組啊贪磺,還是指向指針的指針硫兰,指針數(shù)組,數(shù)組指針等等缘挽,但是我覺得這些東西的本質(zhì)都是內(nèi)存瞄崇,為什么好多底層應(yīng)用都是用C語(yǔ)言呻粹,其中一個(gè)重要的因素就是C語(yǔ)言可以直接操作內(nèi)存壕曼,提供更高效的編程。所以在學(xué)習(xí)指針這部分之前最好先把計(jì)算機(jī)的體系基礎(chǔ)知識(shí)補(bǔ)充一下等浊,至少能區(qū)分出來(lái)內(nèi)存和硬盤之間的區(qū)別吧腮郊,一些人說(shuō)自己學(xué)習(xí)軟件的,卻總在說(shuō)自己手機(jī)內(nèi)存不夠用啊筹燕,只有128G轧飞,下一次得買256G內(nèi)存的手機(jī),我覺得這樣肯定編寫不出好程序撒踪。也不可能理解C語(yǔ)言的指針的真正的妙用过咬。
????????所以C語(yǔ)言指針學(xué)習(xí)其實(shí)就是內(nèi)存的應(yīng)用,如何通過(guò)程序去操作內(nèi)存制妄。這里全部以32位的操作系統(tǒng)為例掸绞,內(nèi)存其實(shí)就是按照字節(jié)(8位的二進(jìn)制數(shù))大小為基本單位,每個(gè)字節(jié)都會(huì)有一個(gè)編號(hào)耕捞,也就是地址衔掸,當(dāng)你訪問(wèn)這個(gè)地址的時(shí)候烫幕,字節(jié)里的8位二進(jìn)制數(shù)就會(huì)被讀出去了,也就是在變量作為賦值運(yùn)算符右值的時(shí)候敞映。在C語(yǔ)言定義變量的時(shí)候较曼,那些類型名如int,char振愿,short等捷犹,其實(shí)就是在內(nèi)存中取出相應(yīng)大小連續(xù)字節(jié)分配到一起,并且以最低的地址作為整個(gè)變量的地址埃疫,比如定義 char c伏恐;就會(huì)在內(nèi)存中分配一個(gè)字節(jié)的內(nèi)存,而編譯器會(huì)把這個(gè)變量名替換為地址栓霜,這樣這個(gè)變量與內(nèi)存就關(guān)聯(lián)起來(lái)了翠桦。在定義int a;此時(shí)就會(huì)分配四個(gè)字節(jié)的內(nèi)存胳蛮,現(xiàn)在就相當(dāng)于把這四個(gè)字節(jié)連接在一起了销凑,整個(gè)四個(gè)字節(jié)以最低的地址作為變量的地址。編譯器將地址與a關(guān)聯(lián)起來(lái)仅炊,編譯為匯編之后斗幼,還是采用地址訪問(wèn)的。這就是變量定義的本質(zhì)抚垄。
????????對(duì)于指針來(lái)說(shuō)蜕窿,其實(shí)就是內(nèi)容裝的是地址而已,對(duì)于它的定義呆馁,在32位系統(tǒng)中桐经,都是分配四個(gè)字節(jié)作為它的內(nèi)存空間,而對(duì)于類型的定義如int*浙滤,char *還是void (*p )(int )??等等阴挣,就是定義了指針內(nèi)存中存在的地址的內(nèi)存中內(nèi)容的解析方式。這句話可能比較繞口纺腊,來(lái)具體解析一下畔咧,比如前面定義的兩個(gè)變量之后,定義兩個(gè)指針揖膜,char *ch=&c誓沸;int * num=&a;這里其實(shí)編譯器給ch和num分配的內(nèi)存都是4個(gè)字節(jié)壹粟,也就是為什么sizeof(指針)都等于4拜隧,其實(shí)從內(nèi)存的角度來(lái)看這個(gè)問(wèn)題,就很明白,而不是去死記硬背虹蓄。這時(shí)候的ch這四個(gè)字節(jié)的內(nèi)容就是100犀呼,num的四個(gè)字節(jié)的內(nèi)容就是400,當(dāng)我們使用*去解析指針的時(shí)候薇组,這個(gè)時(shí)候前面對(duì)于指針類型的聲明才會(huì)起作用外臂,比如 *ch 就是去訪問(wèn)地址100也就是變量c的內(nèi)容,怎么訪問(wèn)呢律胀,是取一個(gè)字節(jié)宋光,兩個(gè)字節(jié)還是四個(gè)字節(jié)的內(nèi)容呢?就是按照指針變量的聲明炭菌,char * 的char來(lái)訪問(wèn)罪佳,因?yàn)閏har就是一個(gè)字節(jié),所以讀取地址100的內(nèi)存處的一個(gè)字節(jié)黑低。對(duì)于 *num就是訪問(wèn)地址400處的內(nèi)存赘艳,訪問(wèn)幾個(gè)字節(jié),你應(yīng)該知道了克握。圖中指針是4個(gè)字節(jié)蕾管,簡(jiǎn)化了。
????????介紹到這里菩暗,如果我沒(méi)有說(shuō)明白掰曾,還是在看看后面的書在深入理解一下吧。這就是變量與指針的本質(zhì)停团,就是內(nèi)存旷坦,但其實(shí)好多C語(yǔ)言的書都沒(méi)有這么介紹,我覺得對(duì)于指針的理解造成一定的難度佑稠。這里就引出了一個(gè)大問(wèn)題秒梅,變量定義的內(nèi)存在哪個(gè)區(qū)域呢,為什么變量在代碼位置不同讶坯,作用域番电,存活時(shí)間都不同呢岗屏?這就是C語(yǔ)言的內(nèi)存分配模型能夠解釋這個(gè)問(wèn)題辆琅。
## C語(yǔ)言內(nèi)存分配模型
?????????對(duì)于C語(yǔ)言內(nèi)存的分配模型主要有這么幾個(gè)區(qū)域,按照從地址由高到底的順序排列(linux下的內(nèi)存分配):棧(由上向下生長(zhǎng))这刷、堆(由下向上生長(zhǎng))婉烟、靜態(tài)存儲(chǔ)區(qū)(.bss和.data)、代碼區(qū)(.text和.rodata).如下圖所示:
????????有了這個(gè)就可以分析C語(yǔ)言的變量的作用域暇屋,存儲(chǔ)類型以及生命周期了似袁。對(duì)于在代碼塊內(nèi)聲明的變量就是局部變量,這樣的變量存儲(chǔ)在棧上,代碼塊結(jié)束就會(huì)釋放昙衅,也是為什么局部變量不初始化時(shí)隨機(jī)值的原因扬霜。全局變量和靜態(tài)變量都存儲(chǔ)在靜態(tài)存儲(chǔ)區(qū),如果初始化不為0就存放在.data段而涉,如果沒(méi)有初始化或者初始化為0著瓶,就會(huì)放在.bss段,所以在整個(gè)程序運(yùn)行期間都活著啼县。代碼就是存放在代碼段材原,一般這個(gè)內(nèi)存區(qū)域都是只讀的,不能向該區(qū)域?qū)懠揪臁?duì)于動(dòng)態(tài)申請(qǐng)的內(nèi)存就是分配在堆中余蟹。我個(gè)人覺得如果你掌握了這個(gè)內(nèi)存空間分配的模型,對(duì)于變量的作用域子刮,存儲(chǔ)類型等等為什么會(huì)與在代碼中聲明的位置有關(guān)威酒,理解起來(lái)會(huì)很有幫助。
## C語(yǔ)言的操作符與表達(dá)式
?????????這是C語(yǔ)言的另一個(gè)難點(diǎn)挺峡,其實(shí)對(duì)于這個(gè)理解起來(lái)呢兼搏,就是結(jié)合C語(yǔ)言的優(yōu)先級(jí)來(lái)分析,因?yàn)閮?yōu)先級(jí)比較多且雜沙郭,具體表格可以查閱相關(guān)書籍佛呻。這里在網(wǎng)上看過(guò)的一個(gè)順口溜,可以幫助記憶病线。
?????????????????????????????????????????小括中括指向點(diǎn), (? "()","[ ]","->", ".")
?????????????????????????????????????????非反后來(lái)自加減; (! ~ ++ --)
?????????????????????????????????????????負(fù)類指針有地址,? (-, 類型轉(zhuǎn)換, *, &)?
?????????????????????????????????????????長(zhǎng)度唯一右在前. (sizeof ,單目運(yùn)算吓著,從右至左)
?????????????????????????????????????????先乘除,再求余, (*, /, %)
?????????????????????????????????????????加減后送挑,左右移, (+, -, <<, >>)
?????????????????????????????????????????關(guān)系運(yùn)算左為先. (<, <=, >, >>)
?????????????????????????????????????????等于還是不等于, (==, !=)
?????????????????????????????????????????按位運(yùn)算與異或; (&, ^, | )
?????????????????????????????????????????邏輯與绑莺,邏輯或, (&&, || )
?????????????????????????????????????????條件運(yùn)算右至左. (? : )
?????????????????????????????????????????賦值運(yùn)算雖然多, (=, +=, -=, *=, /=, %=,>>=, <<=, &=, ^=, |=)
?????????????????????????????????????????從右至左不會(huì)錯(cuò); ( 從右至左)
?????????????????????????????????????????逗號(hào)不是停頓符, ( , )
?????????????????????????????????????????順序求值得結(jié)果. (順序求值運(yùn)算符)
比如*p++,a=1<<2+3惕耕;int *p[10]與int (*p)[10]等等纺裁。我們?cè)诙x一個(gè)符號(hào)時(shí),首先要搞清楚你定義的符號(hào)時(shí)誰(shuí)(第一步:找核心)司澎。
???????復(fù)雜表達(dá)式分析方法
???????我們?cè)诙x一個(gè)符號(hào)時(shí)欺缘,首先要搞清楚你定義的符號(hào)時(shí)誰(shuí)(第一步:找核心)。舉個(gè)例子:int*p[5]這個(gè)式子中p是核心挤安,這里int谚殊、*、中括號(hào)蛤铜、分號(hào)都是為了定義p嫩絮,因此它是核心丛肢。找到核心,第二步找結(jié)合剿干。舉個(gè)例子:int*p這里的核心是p蜂怎,會(huì)和誰(shuí)結(jié)合呢,一個(gè)是*置尔,一個(gè)是分號(hào)派敷;,根據(jù)一般規(guī)律分號(hào)不結(jié)合撰洗,因此p與*結(jié)合篮愉。*p的左邊是int,右邊是分號(hào)差导,因?yàn)榉痔?hào)不結(jié)合试躏,因此*p與int結(jié)合表示p這個(gè)指針指向int型的數(shù)據(jù)。在舉個(gè)例子:int p[5]中设褐,核心是p颠蕴,p左邊是int,右邊是中括號(hào)[]助析,根據(jù)優(yōu)先級(jí)犀被,p與中括號(hào)[]結(jié)合成數(shù)組。p[]左邊是int外冀,右邊是分號(hào)寡键,因?yàn)榉痔?hào)不結(jié)合,所以p[]與int結(jié)合表示數(shù)組中的元素是int型的雪隧。如果核心與*號(hào)結(jié)合西轩,表示核心是指針;如果核心和中括號(hào)結(jié)合[],表示核心是數(shù)組脑沿;如果核心與小括號(hào)結(jié)合()藕畔,表示核心是函數(shù)。
# 三庄拇、書籍推薦
## 入門級(jí)書籍
?????????C語(yǔ)言程序設(shè)計(jì)——現(xiàn)代方法(第2版)
?????????這本書我覺得非常適合入門注服,學(xué)習(xí)C語(yǔ)言的基礎(chǔ)語(yǔ)法,對(duì)于入門真的很友好措近,我在大四重新學(xué)習(xí)C語(yǔ)言的時(shí)候就是學(xué)習(xí)了這本書溶弟,把課后題都親自去敲程序,才真正的入門C語(yǔ)言熄诡,能寫出一些小程序了可很。個(gè)人十分推薦诗力,能夠把基礎(chǔ)打牢凰浮。
## 提升書籍
?????????C與指針
?? ? ? ? ? ??
?????????這本書絕對(duì)是神級(jí)之做我抠,強(qiáng)烈建議讀透,之前大四讀沒(méi)什么感覺袜茧,在經(jīng)歷過(guò)面試的面試題筆試題的洗禮之后菜拓,再次閱讀發(fā)現(xiàn)都是這本書講過(guò)的內(nèi)容,很適合在有一定的基礎(chǔ)之后進(jìn)行拔高笛厦,對(duì)于C語(yǔ)言有更深入的認(rèn)識(shí)纳鼎。在掌握這本書的細(xì)節(jié)之后,基本的C語(yǔ)言知識(shí)應(yīng)該就都掌握了裳凸,不過(guò)一定要腳踏實(shí)地去學(xué)贱鄙。
????????C陷阱與缺陷
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
?????????這本書其實(shí)就是講解了一些C語(yǔ)言的易錯(cuò)點(diǎn),可以作為上一本的補(bǔ)充姨谷,看看自己還哪里有知識(shí)的盲點(diǎn)逗宁。
?????????C專家編程
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
????????這本書我還真沒(méi)看的太懂,畢竟很菜梦湘,不是專家瞎颗。不是很推薦,沒(méi)時(shí)間可以不讀捌议。
????????深入理解C指針
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
在看完前面的c與指針之后哼拔,如果還是對(duì)指針的理解有些疑問(wèn),可以繼續(xù)閱讀這本書籍瓣颅,加深對(duì)指針的理解倦逐。
## 加深理解書籍
???????????嵌入式LINUX與物聯(lián)網(wǎng)軟件開發(fā)??C語(yǔ)言內(nèi)核深度解析
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
????????這本書對(duì)于C語(yǔ)言的內(nèi)存模型講解的十分不錯(cuò),包括位操作等宫补,對(duì)于前面所說(shuō)的內(nèi)存模型理解十分有幫助僻孝。
????????C語(yǔ)言深度解剖(第2版)解開程序員面試筆試的秘密
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
???????這本書其實(shí)很多內(nèi)容都是參考c與指針的,里面有作者的一些經(jīng)驗(yàn)分享以及面試經(jīng)驗(yàn)的分享守谓,里面還有一套測(cè)試題可以用來(lái)測(cè)試自己C語(yǔ)言的水平穿铆。
???????高質(zhì)量程序設(shè)計(jì)指南_C++_C語(yǔ)言(第三版)
???????這本書也是一本很好的書,里面介紹了作者在工作中應(yīng)用C語(yǔ)言和c++的寶貴經(jīng)驗(yàn)斋荞,對(duì)于使用C語(yǔ)言的代碼規(guī)范很有幫助荞雏。
#???四、總結(jié)
????????這就是我本人在學(xué)習(xí)C語(yǔ)言里的一些經(jīng)驗(yàn)平酿,希望能給后來(lái)者提供一些參考凤优,節(jié)約一些在書海中尋找好書的時(shí)間,當(dāng)然還有很多優(yōu)秀的書籍蜈彼,我沒(méi)有讀過(guò)筑辨,但是我相信讀完這些推薦的書籍,你在C語(yǔ)言的理解上肯定會(huì)更近一步的幸逆,起碼在招聘的C語(yǔ)言基礎(chǔ)部分是沒(méi)有問(wèn)題的棍辕。當(dāng)然暮现,學(xué)的知識(shí)還是重在實(shí)踐,還是要找一些可以應(yīng)用的項(xiàng)目去學(xué)習(xí)楚昭,把前面學(xué)到的c語(yǔ)言知識(shí)應(yīng)用起來(lái)栖袋,我就是把這些知識(shí)應(yīng)用到修改了之前的實(shí)驗(yàn)室用于項(xiàng)目的代碼中去了。