C語言常見指針應(yīng)用-Half_word編寫
C語言常見指針應(yīng)用
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? -Half_word編寫
簡單級別:
前言:
首先簡單回顧一下:C語言普通變量名/標號代表隊<int Alex = 32;? char Tina = ‘a(chǎn)’… …>
這是初學C語言時候‘結(jié)識’的‘好漢’ ;對于其使用不再贅述(無外乎賦值,邏輯運算等)。本章來聊一聊這些普通的變量的“深層“內(nèi)涵;一個變量的聲明等同于給內(nèi)存中某個地址單元起別名,而賦值等操作等價于在這個單元上進行的各類值傳遞(可以從下表窺探一二);變量具體占內(nèi)存空間(通俗而言就是有多少個單元)由聲明的類型決定。

傳遞給變量的值可以多種,只要合法(與聲明時的類型對應(yīng))。
這樣的變量使用較為簡單,但是… …,有這樣的需求:每次給這個變量賦值都要拿出變量名,一兩個倒是能接受,要是有一堆變量(萬一類型還各不一樣),重復(fù)度太高。我想高效點,用一個東西就可以改變他們所有的值。So,我們需要找出這些類型不同的變量之間的“通信證“----內(nèi)存地址。
計算機的角度看:程序皆數(shù)據(jù);所以得地址者得天下
所以,引出今天的“難一號”----指針;有同學會問,指針不是也只能存放對應(yīng)類型的地址嗎?
這個答案并不對,既然是地址,就沒有類型之分,它只是記錄一個相對的偏移量數(shù)值,因此其大小是個定值。
那得到地址后如何區(qū)分該進行哪些數(shù)據(jù)的修改呢?
這一問題的答案剛好解釋前一問題。能修改多少取決于你給這個指針的類型決定(比如這個指針是char* p;那么它指向的地址單元起你可以修改sizeof(char)個字節(jié))。
意味著:指針僅僅得到了一個地址值,天下指針一個樣。
實例:
char* p1 = &Tina;
int* p2 = &Alex;

(PS: 要是有童鞋喜歡鉆研可以聲明多個不同類型的指針,通過sizeof運算符檢驗它們的大小,你會得出上述結(jié)論的)
?。?!既然天下指針“都一樣“;為了方便,我們一個指針是不是就可以開遍整個“小區(qū)”呢?YES,不過需要一些手段----強制類型轉(zhuǎn)換
(PS: 有些類型的強制轉(zhuǎn)換過于繁瑣,有的甚至你找不出對應(yīng)的強制轉(zhuǎn)換類別,即可以聲明那種指針。但是強制類型轉(zhuǎn)換那種指針編譯器不能通過)


至于更多的類型值修改,參照上述方案,需要自己動手好好揣摩其中的轉(zhuǎn)換。
(PS:指針本身也是一個內(nèi)存中的數(shù)據(jù);所以,只要指的好,指針也能變工具人的工具)
所以在今后的指針使用中應(yīng)當注意的是指向的類型大小, 對于指針本身而言在其次。
練一練:
? ? ? ? ?? char arr[9] = “ABCDEF”;
? ? ? ? ? ? int* p;
? ? ? ? ? ? 用p將arr內(nèi)的字母變?yōu)樾憽?/p>
?總結(jié):天下指針皆一家,只要目標的大小和地址已知,一個指針就能改遍內(nèi)存
?中級級別:
經(jīng)過前面的學習,我們知道了指針是輔助修改內(nèi)存中的值的這樣一種特殊存在;
但是,我們會發(fā)現(xiàn)這樣一個問題,那些基本變量類型大小都是丹尼斯·里奇的藍圖下給的,要修改就不得不找準大小,否則引起內(nèi)存數(shù)據(jù)錯亂,重則引發(fā)程序崩潰。
那么,有沒有可以自由支配的大小內(nèi)存塊呢?
答案是有的,為了保證C語言的高靈活性(較之匯編等低級語言),malloc()函數(shù)應(yīng)運而生。
從而也有了一系列的內(nèi)存泄漏等等事故(??開玩笑的)。這個函數(shù)就是為了給用戶申請自定義大小的內(nèi)存空間并且返回該處內(nèi)存空間首地址的“好東西“;
例如:int* p3 = malloc(1024);//向內(nèi)存要了1024字節(jié)(1kb)的空間.
有了這個地址,我們就可以向一大片內(nèi)存注入數(shù)據(jù)了。但是,一個地址一個地址的寫數(shù)據(jù)又回歸了機器語言的時代了。
我們需要規(guī)范的寫入一系列有用的值(比如在這片內(nèi)存記錄下MM的QQ號、微信號、年齡(問就是18))。
所以我們就找到了C語言的模板設(shè)計師----struct結(jié)構(gòu)體家族,幫助你管理申請的內(nèi)存空間數(shù)據(jù)寫入;具體設(shè)計操作見下代碼:
struct MM_info {
?char name[20];
??? ?unsiged char age;//150歲以上的就別管了,國家的
?? char Q_nub[11];
/*… …其它暫不定義寫入… …*/
??? ?struct MM* next;
};
struct MM* info_A = malloc(1024);
現(xiàn)在我們就可以通過info_A這個有特定模板的指針對申請到的匿名內(nèi)存進行讀寫操作了,具體操作由模板內(nèi)的類型聲明決定。
如:
info_A -> age = 1;?
對于申請的內(nèi)存在單次最大值限制,所以我們在實際工程開發(fā)的時候?qū)τ谝粋€模板還會引入
一個指向這個模板類型的指針,并且用其存放下一個匿名內(nèi)存塊的起始地址;這就形成了一種鏈式的數(shù)據(jù)結(jié)構(gòu)----鏈表。在鏈表的基礎(chǔ)上延伸出的圖、樹此類皆是同原理,區(qū)別就是指針數(shù)目不同。
我們可以通過這些模板操作匿名內(nèi)存,做一些高級的數(shù)據(jù)結(jié)構(gòu)設(shè)計;甚至用這樣的數(shù)據(jù)結(jié)構(gòu)開發(fā)系統(tǒng)。
(具體有哪些數(shù)據(jù)結(jié)構(gòu)和相關(guān)一些算法參考相關(guān)書籍,如:《趣學數(shù)據(jù)結(jié)構(gòu)》等)
針對匿名內(nèi)存,除申請和使用還應(yīng)當注意的是釋放內(nèi)存,對于那些使用完的內(nèi)存如果不釋放就會產(chǎn)生開頭所說的內(nèi)存泄露了,對于內(nèi)存來說這是災(zāi)難。
應(yīng)當注意:每次malloc()等申請內(nèi)存操作完成后皆需調(diào)用free()釋放已用完的內(nèi)存區(qū),安全第一。

函數(shù)指針的出現(xiàn)使得原本就很復(fù)雜的指針類型圈又濃墨重彩的添加了一筆。
我們對于一個函數(shù)聲明到定義,處理通常有兩種處理思路:1.先聲明后定義;2.直接給出定義,但是這種多見于單文件編譯的情況。
既然是定義,就會在內(nèi)存中占據(jù)空間,函數(shù)名(標號)顯式的占據(jù)了空間,肯定會給出尋找這片內(nèi)存起始地址的方法;沒錯,就是那個定義函數(shù)的的函數(shù)名,main函數(shù)也不例外的有它的起始地址(AT&T匯編結(jié)果顯示其起始地址為0x0000,有興趣的小伙伴可以通過gcc -S查看相關(guān)匯編代碼)。
只要用指針找到這片內(nèi)存就可以對其進行使用。這似乎和前面講的簡單的指針使用是一樣的… …(細品品好像漏了點東西)
BUT函數(shù)還有一大重要的屬性----參數(shù);前面的內(nèi)存里面的數(shù)據(jù)我們只是當成了數(shù)據(jù)并且進行相應(yīng)的操作,對于函數(shù)標號所在的那片內(nèi)存空間的數(shù)據(jù),我們需要把它們看做一條條的指令而不是一大串數(shù)據(jù)。
因而聲明一個函數(shù)指針時你需要進行有效的內(nèi)存引導,而不能進行匿名內(nèi)存的使用(除非您手寫機器代碼進該內(nèi)存空間)

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 筆者水平有限,只能分享這些淺顯的指針使用,如有不足處請多多指教