2012軟件水平設(shè)計師:C語言指針引發(fā)的聯(lián)想
剛接觸編程的時候,用的就是C語言,學(xué)的時候用的開發(fā)軟件是Turbo C,很經(jīng)典的一款I(lǐng)DE了(現(xiàn)在應(yīng)該沒人在用了吧)。剛學(xué)習(xí)C的時候,主要就是學(xué)習(xí)其語法,先用一些語法來做出一些簡單的小功能,寫一些簡單的小邏輯。
學(xué)著學(xué)著,就學(xué)到了指針了,我記得那本書上講了,指針是C的核心,學(xué)C語言一定要掌握指針。知道了其重要性之后,就更加認(rèn)真地去學(xué),不過當(dāng)時還不清楚為什么C的指針是那么重要,它到底有什么影響。后來一步一步地學(xué)習(xí),通過了解其它的相關(guān)知識,順藤摸瓜地了解到了很多之前不懂的東西。我也十分不了解,為什么要叫成指針呢?當(dāng)然我個人對這個名字還是挺不爽的。因為首先名字就給人感覺很深奧、很難以理解。
其實說白了指針就是一種數(shù)據(jù)類型(int 、char、double),指針,說到底它還是一個變量,跟int、char類型的變量無性質(zhì)差別。由于指針存的是一個內(nèi)存地址,所以指針類型的變量所占的字節(jié)大小,會因它所處在的CPU所能尋址到的地址值有關(guān)。
說到內(nèi)存地址,那么必須簡單了解下計算機(jī)的運作。一個程序是怎么運行起來的呢?這是CPU的功勞了,CPU的全稱“中央處理器”,聽到中央兩個字就知道它有多么重要了。不過說白了CPU就是一個處理器,它處理的目標(biāo)是指令,指令就是二進(jìn)制,CPU它做的是最苦最累的一份活了,沒有目的的,沒有止境地讀出一條指令,執(zhí)行它,然后下一條,指令它,它的好處是,它不會出錯,真有一天它出錯了,那么一定是你的錯。當(dāng)你的CPU燒了的時候,請諒解它,并檢討下平時怎么虐待它的。然后再買個更經(jīng)得起虐待的CPU。
對了,CPU它的指令是從哪里來的呢?--可執(zhí)行程序,可執(zhí)行程序存在硬盤上,可是CPU到硬盤拿數(shù)據(jù)的速度太慢了(我也問過為什么不能做到很快)。眾所周知,CPU運算速度那不是普通地快的,所以怎么能允許硬盤拖后腿呢,這樣的話,變成CPU跟硬盤一樣快了(不怕狼一樣的敵人,就怕豬一樣的隊友,硬盤會降低CPU的智商的)?所以內(nèi)存它登場了,CPU跟內(nèi)存打交道的速度則相對較快,總之比硬盤快太多太多了(所以內(nèi)存比硬盤貴,內(nèi)存4G多少錢,硬盤500G多少?差價太多啦)。不過CPU其實還是不怎么喜歡跟內(nèi)存打交道(主要原因還是:CPU真TM太快了,內(nèi)存還是很慢),所以CPU跟內(nèi)存之間本身還有一層緩存,就是我們平時說的一級緩存、二級緩存,這個緩存造價相對比內(nèi)存要貴得多,所以容量也不大,這樣就更需要有效地利用了。執(zhí)行一個文件,大體的流程是這樣:CPU從硬盤上讀出這個文件,再把這個文件載入到內(nèi)存上,此后就通過內(nèi)存來交互了。
內(nèi)存,其實就是由很多個字節(jié)有序組成的一塊東東,比如說1G的內(nèi)存條,那么就是由1024*1024*1024大小的字節(jié)組成。記得我那時候剛接觸計算機(jī)的時候,聽說一個進(jìn)程的內(nèi)存空間是4G(32位操作系統(tǒng),32位CPU下),那假如我僅有1G的物理內(nèi)存呢(我配的電腦內(nèi)存是1G的)?進(jìn)程的內(nèi)存是多少?還是4G!這就涉及到了虛擬內(nèi)存的概念了。越扯越遠(yuǎn)了,虛擬內(nèi)存就是把硬盤的空間當(dāng)成“內(nèi)存”來用,具體怎么用呢?其實就是交換了,把當(dāng)前內(nèi)存上的不那么重要的數(shù)據(jù),寫在硬盤上,騰出更多的物理空間來給我們的程序,那么硬盤充當(dāng)?shù)慕巧褪翘摂M空間了,至于選哪些數(shù)據(jù)放到硬盤上,系統(tǒng)有它的一套選擇方式。像WINDOWS下有pagefile.sys這個文件,linux下有swap分區(qū),其實就是拿來做交換存放用的。由于上面講過了,CPU直接讀硬盤是非常慢的,虛擬內(nèi)存是能力有限的,所以如果想機(jī)子快一點的話,還是乖乖地加多物理內(nèi)存吧。
對于匯編程序來說,基本上沒有什么數(shù)據(jù)類型的概念的,在匯編程序中,如果想定義一個數(shù)字,要先衡量下這個數(shù)值將會用到的最小值,從而來決定要多少個字節(jié)來存儲。是的,C的數(shù)據(jù)類型也是這個概念,int值跟short沒什么本質(zhì)差別,就是字節(jié)數(shù)的不同而已,C語言在編譯的時候,就是把C代碼翻譯成匯編,所謂的編譯器就是干的這事,它就是一個翻譯軟件,從一門語言翻譯成另一門語言,如果定義了一個int變量,那么編譯的時候,編譯器會分配4個字節(jié)的空間來存放那個變量(不考慮字節(jié)對齊的情況)。
為啥說C語言是一門很靈活的語言呢?那是因為它有了指針,為什么指針就那么了不起呢?原因很簡單,你可以訪問整個內(nèi)存地址,你想訪問哪里,就直接指過去,比如你知道在內(nèi)存里第0x1000個字節(jié)里面存有你需要的數(shù)據(jù),你可以直接把一個指針賦值成0x1000,然后通過*號進(jìn)行解引用取得值(在以前的操作系統(tǒng)中,操作內(nèi)存的自由度比較高,但在現(xiàn)在整個物理內(nèi)存的管理是由操作系統(tǒng)管理好的了,每一個字節(jié)都在它的掌握中,你亂指的話,系統(tǒng)直接把你崩潰掉,至少你的程序不會影響到其它進(jìn)程)。C提供的思想是:程序員永遠(yuǎn)都清楚自己在做什么,就算指針亂指(野指針)導(dǎo)致程序錯誤,那么也是由程序員自己負(fù)責(zé),所以……,指針這把鋒利的刀,用起來方便,但也很容易傷了自己。跟其它語言不一樣,像JAVA里面只有引用,引用原理上來講也是一個指針,但是這個指針并不能讓你隨心所欲地用,這個引用只能指向你可以指的東西。因為JAVA本身有對引用進(jìn)行管理,所以安全性則相對較高。
對于指針,最常見的情況下是用來對某一個變量做修改,如果在一個函數(shù)里面?zhèn)饕粋€int值的參數(shù)進(jìn)去:
int fun(int a)
{
a = 10;
return a;
}
int b = 0;
fun(b);
這樣調(diào)用后b是不會有變化的,因為傳進(jìn)去函數(shù)的參數(shù),在傳進(jìn)去的時候,僅僅只是一個拷貝而已,但是如果
int fun(int* a)
{
*a = 10;//通過解引用給那個地址里面的內(nèi)容賦值成10
}
fun(&b);
這樣把b的地址傳過去,那么a就是b的地址的拷貝(這里也是有拷貝,只是說拷貝的是一個地址,并不是內(nèi)容),但是通過a里面存著的地址,從而找到這個地址里面的內(nèi)容(星號是取地址內(nèi)容),把這個地址的內(nèi)容改寫成10,那樣的話,b才真正給改變了。
OK,亂扯完畢,可能有些東西并不是太嚴(yán)謹(jǐn),不過大體意思知道就好了。
剛接觸編程的時候,用的就是C語言,學(xué)的時候用的開發(fā)軟件是Turbo C,很經(jīng)典的一款I(lǐng)DE了(現(xiàn)在應(yīng)該沒人在用了吧)。剛學(xué)習(xí)C的時候,主要就是學(xué)習(xí)其語法,先用一些語法來做出一些簡單的小功能,寫一些簡單的小邏輯。
學(xué)著學(xué)著,就學(xué)到了指針了,我記得那本書上講了,指針是C的核心,學(xué)C語言一定要掌握指針。知道了其重要性之后,就更加認(rèn)真地去學(xué),不過當(dāng)時還不清楚為什么C的指針是那么重要,它到底有什么影響。后來一步一步地學(xué)習(xí),通過了解其它的相關(guān)知識,順藤摸瓜地了解到了很多之前不懂的東西。我也十分不了解,為什么要叫成指針呢?當(dāng)然我個人對這個名字還是挺不爽的。因為首先名字就給人感覺很深奧、很難以理解。
其實說白了指針就是一種數(shù)據(jù)類型(int 、char、double),指針,說到底它還是一個變量,跟int、char類型的變量無性質(zhì)差別。由于指針存的是一個內(nèi)存地址,所以指針類型的變量所占的字節(jié)大小,會因它所處在的CPU所能尋址到的地址值有關(guān)。
說到內(nèi)存地址,那么必須簡單了解下計算機(jī)的運作。一個程序是怎么運行起來的呢?這是CPU的功勞了,CPU的全稱“中央處理器”,聽到中央兩個字就知道它有多么重要了。不過說白了CPU就是一個處理器,它處理的目標(biāo)是指令,指令就是二進(jìn)制,CPU它做的是最苦最累的一份活了,沒有目的的,沒有止境地讀出一條指令,執(zhí)行它,然后下一條,指令它,它的好處是,它不會出錯,真有一天它出錯了,那么一定是你的錯。當(dāng)你的CPU燒了的時候,請諒解它,并檢討下平時怎么虐待它的。然后再買個更經(jīng)得起虐待的CPU。
對了,CPU它的指令是從哪里來的呢?--可執(zhí)行程序,可執(zhí)行程序存在硬盤上,可是CPU到硬盤拿數(shù)據(jù)的速度太慢了(我也問過為什么不能做到很快)。眾所周知,CPU運算速度那不是普通地快的,所以怎么能允許硬盤拖后腿呢,這樣的話,變成CPU跟硬盤一樣快了(不怕狼一樣的敵人,就怕豬一樣的隊友,硬盤會降低CPU的智商的)?所以內(nèi)存它登場了,CPU跟內(nèi)存打交道的速度則相對較快,總之比硬盤快太多太多了(所以內(nèi)存比硬盤貴,內(nèi)存4G多少錢,硬盤500G多少?差價太多啦)。不過CPU其實還是不怎么喜歡跟內(nèi)存打交道(主要原因還是:CPU真TM太快了,內(nèi)存還是很慢),所以CPU跟內(nèi)存之間本身還有一層緩存,就是我們平時說的一級緩存、二級緩存,這個緩存造價相對比內(nèi)存要貴得多,所以容量也不大,這樣就更需要有效地利用了。執(zhí)行一個文件,大體的流程是這樣:CPU從硬盤上讀出這個文件,再把這個文件載入到內(nèi)存上,此后就通過內(nèi)存來交互了。
內(nèi)存,其實就是由很多個字節(jié)有序組成的一塊東東,比如說1G的內(nèi)存條,那么就是由1024*1024*1024大小的字節(jié)組成。記得我那時候剛接觸計算機(jī)的時候,聽說一個進(jìn)程的內(nèi)存空間是4G(32位操作系統(tǒng),32位CPU下),那假如我僅有1G的物理內(nèi)存呢(我配的電腦內(nèi)存是1G的)?進(jìn)程的內(nèi)存是多少?還是4G!這就涉及到了虛擬內(nèi)存的概念了。越扯越遠(yuǎn)了,虛擬內(nèi)存就是把硬盤的空間當(dāng)成“內(nèi)存”來用,具體怎么用呢?其實就是交換了,把當(dāng)前內(nèi)存上的不那么重要的數(shù)據(jù),寫在硬盤上,騰出更多的物理空間來給我們的程序,那么硬盤充當(dāng)?shù)慕巧褪翘摂M空間了,至于選哪些數(shù)據(jù)放到硬盤上,系統(tǒng)有它的一套選擇方式。像WINDOWS下有pagefile.sys這個文件,linux下有swap分區(qū),其實就是拿來做交換存放用的。由于上面講過了,CPU直接讀硬盤是非常慢的,虛擬內(nèi)存是能力有限的,所以如果想機(jī)子快一點的話,還是乖乖地加多物理內(nèi)存吧。
對于匯編程序來說,基本上沒有什么數(shù)據(jù)類型的概念的,在匯編程序中,如果想定義一個數(shù)字,要先衡量下這個數(shù)值將會用到的最小值,從而來決定要多少個字節(jié)來存儲。是的,C的數(shù)據(jù)類型也是這個概念,int值跟short沒什么本質(zhì)差別,就是字節(jié)數(shù)的不同而已,C語言在編譯的時候,就是把C代碼翻譯成匯編,所謂的編譯器就是干的這事,它就是一個翻譯軟件,從一門語言翻譯成另一門語言,如果定義了一個int變量,那么編譯的時候,編譯器會分配4個字節(jié)的空間來存放那個變量(不考慮字節(jié)對齊的情況)。
為啥說C語言是一門很靈活的語言呢?那是因為它有了指針,為什么指針就那么了不起呢?原因很簡單,你可以訪問整個內(nèi)存地址,你想訪問哪里,就直接指過去,比如你知道在內(nèi)存里第0x1000個字節(jié)里面存有你需要的數(shù)據(jù),你可以直接把一個指針賦值成0x1000,然后通過*號進(jìn)行解引用取得值(在以前的操作系統(tǒng)中,操作內(nèi)存的自由度比較高,但在現(xiàn)在整個物理內(nèi)存的管理是由操作系統(tǒng)管理好的了,每一個字節(jié)都在它的掌握中,你亂指的話,系統(tǒng)直接把你崩潰掉,至少你的程序不會影響到其它進(jìn)程)。C提供的思想是:程序員永遠(yuǎn)都清楚自己在做什么,就算指針亂指(野指針)導(dǎo)致程序錯誤,那么也是由程序員自己負(fù)責(zé),所以……,指針這把鋒利的刀,用起來方便,但也很容易傷了自己。跟其它語言不一樣,像JAVA里面只有引用,引用原理上來講也是一個指針,但是這個指針并不能讓你隨心所欲地用,這個引用只能指向你可以指的東西。因為JAVA本身有對引用進(jìn)行管理,所以安全性則相對較高。
對于指針,最常見的情況下是用來對某一個變量做修改,如果在一個函數(shù)里面?zhèn)饕粋€int值的參數(shù)進(jìn)去:
int fun(int a)
{
a = 10;
return a;
}
int b = 0;
fun(b);
這樣調(diào)用后b是不會有變化的,因為傳進(jìn)去函數(shù)的參數(shù),在傳進(jìn)去的時候,僅僅只是一個拷貝而已,但是如果
int fun(int* a)
{
*a = 10;//通過解引用給那個地址里面的內(nèi)容賦值成10
}
fun(&b);
這樣把b的地址傳過去,那么a就是b的地址的拷貝(這里也是有拷貝,只是說拷貝的是一個地址,并不是內(nèi)容),但是通過a里面存著的地址,從而找到這個地址里面的內(nèi)容(星號是取地址內(nèi)容),把這個地址的內(nèi)容改寫成10,那樣的話,b才真正給改變了。
OK,亂扯完畢,可能有些東西并不是太嚴(yán)謹(jǐn),不過大體意思知道就好了。