笨鳥先飛學(xué)編程系列之一理解程序中的數(shù)據(jù)
說(shuō)實(shí)話,我還沒(méi)有想好這個(gè)系列到底該怎么講,今天下午粗略的想了下,我覺(jué)得程序都是靠代碼來(lái)操作數(shù)據(jù)的,所以,我就起了這么個(gè)破標(biāo)題。由于我本身水平實(shí)在是菜的可以,所以我理解的絕對(duì)不可能一點(diǎn)錯(cuò)誤沒(méi)有,只希望能通過(guò)我寫的這些文字讓更多的入門編程這個(gè)精彩的世界,倘若讀者發(fā)現(xiàn)我寫的有錯(cuò)誤的地方,一定要回帖告知我改之,以免誤人子弟,再次謝過(guò)。
先說(shuō)一下這篇文字主要內(nèi)容。
- 什么是數(shù)據(jù)及其在電腦中的存儲(chǔ)方式。
- 數(shù)據(jù)類型 —— 區(qū)分?jǐn)?shù)據(jù)的唯一指標(biāo)。
- 變量的定義和使用方法。
- 結(jié)束語(yǔ)。
下面開(kāi)始進(jìn)入正題。
一、 什么是數(shù)據(jù)及其在電腦中的存儲(chǔ)方式。
學(xué)過(guò)計(jì)算機(jī)基礎(chǔ)知識(shí)的朋友,尤其是學(xué)過(guò)編程的朋友,一定知道,現(xiàn)在的CPU是只認(rèn)識(shí)二進(jìn)制數(shù)據(jù)的,也只能進(jìn)行二進(jìn)制的數(shù)值運(yùn)算,在實(shí)際操作中,由于二進(jìn)制太過(guò)煩瑣,而且容易失誤,外加上十六進(jìn)制與二進(jìn)制之間在轉(zhuǎn)換有很多的方便,所以一般的用十六進(jìn)制表示其二進(jìn)制數(shù)值:因此,我們看到的一些編輯器,調(diào)試器等分析出來(lái)的機(jī)器碼都是十六進(jìn)制的。(事無(wú)巨細(xì),如果不明白十六進(jìn)制、十進(jìn)制、二進(jìn)制等概念的朋友,請(qǐng)自行百度“進(jìn)制轉(zhuǎn)換”和“原反補(bǔ)碼”)
1. 什么是數(shù)據(jù)。
好現(xiàn)在讓我們開(kāi)下OD,看看下它分析出來(lái)的數(shù)據(jù)是什么模樣:

如果你細(xì)心觀察,就會(huì)發(fā)現(xiàn),OD的數(shù)據(jù)視圖中,用一些虛豎線,將這些數(shù)據(jù)每4個(gè)一組分割開(kāi)了,如上圖。
讓我們?cè)倏聪峦ㄓ眉拇嫫鳌⒖炊褩#缦聢D:

也都是4個(gè)一組,為什么呢?
現(xiàn)在主流的 操作系統(tǒng) 如(X86 XPSP6 等OS)都是32位的操作系統(tǒng),這些操作系統(tǒng)在32位的硬件環(huán)境下,能夠直接處理32位的數(shù)據(jù),而且,數(shù)據(jù)以32位的單位對(duì)齊運(yùn)行速度也是最快的,如果大家熟悉各進(jìn)制之間轉(zhuǎn)換的話,應(yīng)該知道,十六進(jìn)制與二進(jìn)制之間的轉(zhuǎn)換格式是1比4,就是說(shuō),1個(gè)十六進(jìn)制的數(shù)能代表4位二進(jìn)制的數(shù)據(jù),(0xFF 就是二進(jìn)制的 1111 1111),八個(gè)十六進(jìn)制的數(shù)就是32位了!
2. 數(shù)據(jù)在電腦中的存儲(chǔ)方式
這些數(shù)據(jù)在存放到內(nèi)存里的時(shí)候,有兩種存放方式,學(xué)名字叫:Big Endian 和 Little Endian 。
這兩個(gè)存取方式?jīng)Q定了內(nèi)存存放數(shù)據(jù)的原則是 高高低低 原則 還是 高低低高 原則,比如:我有一個(gè)數(shù)據(jù),是0xA5A1,它在存放到內(nèi)存中是怎樣存放的呢?如果存成A5A1那就是高高低低存放的,如上圖選中的部分,因?yàn)樵谖覀兤綍r(shí)的書寫中,A5是高位,A1在低位,存放到內(nèi)存中的時(shí)候,如上圖,A1存放在00438400這個(gè)位置,而A5存放在00438401這個(gè)位置,高位存放在內(nèi)存的高地址中,低位存放在低地址中,這種方式就是Little Endian,另一種方式就是Big Endian,現(xiàn)在絕大多數(shù)都是使用Little Endian 方式存放的(至今我還沒(méi)有見(jiàn)到過(guò)Big Endian方式存數(shù)的數(shù)據(jù)。),如上圖中大家看到的A1A50000這個(gè)數(shù)據(jù),其實(shí)它的真實(shí)的內(nèi)容是:0x0000A5A1。
到這里大家可能有個(gè)疑問(wèn):如果我要存一堆小的數(shù)據(jù),每個(gè)數(shù)據(jù)都在內(nèi)存里占4個(gè)字節(jié)的位置,是不是太占資源了啊!再說(shuō),如果我要存放的一個(gè)數(shù)據(jù)遠(yuǎn)大于0xFFFFFFFF,怎么辦啊,如果我要存放的數(shù)據(jù)是:0x0089D8F4D326849A,在內(nèi)存是會(huì)是什么樣子呢?如下圖:

如果我們按照我們剛才的分析方法,這個(gè)64位的大數(shù)就被分成了兩個(gè)數(shù):0xD326849A和0x0089D8F4 這顯然是錯(cuò)誤的,那我們?cè)趺磥?lái)表示,怎么才能不讓程序讀一個(gè)錯(cuò)誤的數(shù)據(jù)出來(lái)呢?那就要提前規(guī)定好數(shù)據(jù)的大小。
二、 數(shù)據(jù)類型 —— 區(qū)分?jǐn)?shù)據(jù)的唯一指標(biāo)。
通過(guò)上一章節(jié)的講解,我們知道,要想完整的讀取出一個(gè)數(shù)據(jù),必須提前知道這個(gè)數(shù)據(jù)的大小。那么我們?cè)趺粗阑蛘咴趺匆?guī)定一個(gè)數(shù)據(jù)的大小呢?本小節(jié)就來(lái)解決這個(gè)問(wèn)題。
1. 什么是數(shù)據(jù)類型。
在日常生活中,我們經(jīng)常把一些物品,事物歸類處理,由此我們可以大概的猜測(cè)出來(lái)數(shù)據(jù)類型它的作用是什么。
數(shù)據(jù)類型的作用就是讓程序知道自己要從內(nèi)存里讀多大的一個(gè)數(shù)據(jù)出來(lái)!比如上圖中的大數(shù),我可以只讀一個(gè)0x9A出來(lái),也可以讀0x849A等等。
如果大家有看過(guò)編程相關(guān)的書,那一定看到過(guò)什么整型,字符型,邏輯布爾型,數(shù)組,結(jié)構(gòu)體類型,等等一大堆!再什么時(shí)候該用什么類型,在不同類型的數(shù)據(jù)之間進(jìn)行相互轉(zhuǎn)換的時(shí)候,犯愁了,不知道怎么樣轉(zhuǎn)換才合法,怎么樣轉(zhuǎn)換數(shù)據(jù)才能正常?
在一小節(jié),我們就來(lái)剖析一下我們常見(jiàn)的數(shù)據(jù)類型。
其實(shí),我們沒(méi)有必要關(guān)心那么多數(shù)據(jù)類型的,只要知道,數(shù)據(jù)類型就是定義數(shù)據(jù)的大小,這一句就足夠了:
Ø BYTE就是一個(gè)字節(jié)的大小,如上圖中9A就是一個(gè)BYTE類型的數(shù)據(jù),
Ø int ,DWORD就是兩個(gè)字節(jié)的大小,如上圖中849A就是個(gè)DWORD或者int類型的數(shù)據(jù)
Ø 其它更大的類型(如INT64 等)……
以后,在編程的時(shí)候,當(dāng)我們需要進(jìn)行類型轉(zhuǎn)換的時(shí)候,只要知道,小的數(shù)據(jù)類別往大數(shù)據(jù)類別上轉(zhuǎn)換沒(méi)有問(wèn)題,反過(guò)來(lái)由于內(nèi)存分配的空間不夠就會(huì)導(dǎo)致數(shù)據(jù)丟失,精確度不高等問(wèn)題!
下面我們來(lái)看一下小數(shù)(浮點(diǎn)類型:float)在內(nèi)存里的表示方法:

大家看到,這個(gè)表示的數(shù)據(jù),貌似不是小數(shù)啊,而且這個(gè)數(shù)據(jù),跟上面圖中的數(shù)據(jù)沒(méi)有什么區(qū)別啊,都是一個(gè)模樣……
讓我們?cè)趽Q個(gè)視圖,在OD的數(shù)據(jù)區(qū)右擊,選擇float,如下圖:

數(shù)據(jù)變成這個(gè)樣子了:

哈哈,這樣就清楚了,我們的數(shù)據(jù)是圓周率…(至于小數(shù)與十六進(jìn)制轉(zhuǎn)換的問(wèn)題,大家可以自行百度,這里不做具體講解)。
到這里,我們就又知道數(shù)據(jù)類型的另一個(gè)作用:數(shù)據(jù)類型就是規(guī)定數(shù)據(jù)的表現(xiàn)形式,同樣的內(nèi)存數(shù)據(jù),它可以是一個(gè)整數(shù)也可以是一個(gè)小數(shù),甚至是一個(gè)字母或者漢字……
為了證明這一點(diǎn),我們?cè)僬f(shuō)一下字符,漢字等的概念:
就像大家如上面的小數(shù)中看到的一樣,其實(shí)電腦遠(yuǎn)沒(méi)有人腦智能,它根本不認(rèn)識(shí)什么小數(shù),什么字符什么整數(shù),它認(rèn)識(shí)的只是1和0這兩個(gè)數(shù),其它的它都不認(rèn)識(shí),因此我們說(shuō)的字母,標(biāo)點(diǎn)符號(hào),漢字等等也都是一樣的,其實(shí)在計(jì)算機(jī)的世界里,大家看到的那些文字,其實(shí)都是寫數(shù)字,只不過(guò)是因?yàn)閿?shù)據(jù)類型的特性讓它顯示成了漢字,字母等。如下圖:

如上圖,其實(shí),大家可以看到“關(guān)閉”的文字,其實(shí)它的數(shù)據(jù)在內(nèi)存中被表示成了:B9 D8 B1 D5。
如果大家以DWORD形式讀出來(lái),數(shù)據(jù)就是0xD5B1D8B9,一個(gè)很大的數(shù)字!
看到上圖中的“sOK”這三個(gè)字母了嗎?他們的數(shù)據(jù)就是73 4F 4B,如果大家有ASCII表的話,一查就能知道,由此可見(jiàn),其實(shí),電腦識(shí)別字母也好,識(shí)別漢字也好,其實(shí)都是根據(jù)表硬轉(zhuǎn)換過(guò)來(lái)的,隨便一個(gè)數(shù)據(jù),他都能轉(zhuǎn)換,順利的話,轉(zhuǎn)換出來(lái)的就是我們能識(shí)別的漢字,不順利的話,轉(zhuǎn)換出來(lái)的就是一堆亂碼……
如果細(xì)心的朋友,可能發(fā)現(xiàn)一個(gè)問(wèn)題,我們說(shuō):數(shù)據(jù)類型決定了數(shù)據(jù)的大小和表現(xiàn)形式,那一個(gè)字符串怎么規(guī)定大小啊?難道還有4個(gè)字節(jié)大小的字符串,12個(gè)字節(jié)大小的字符串類型?
哈哈,其實(shí),字符串就是一個(gè)連續(xù)的BYTE(或者char)類型的數(shù)據(jù)串,由于字符串可大可小,不可以具體規(guī)定它有多大,所以大家都規(guī)定,字符串以0結(jié)尾,如果要從內(nèi)存里將數(shù)據(jù)以一個(gè)字符串的形式讀出來(lái)的話,那程序就是從字符串的第一個(gè)字符開(kāi)始,一直讀到0 處,算做讀取完畢。
2. 字符編碼問(wèn)題。
既然提到漢字,就不能不提Unicode編碼,很多的同學(xué)對(duì)這個(gè)編碼問(wèn)題很是迷茫,總是把這個(gè)跟數(shù)據(jù)類型混淆在一起,所以我就把這兩個(gè)問(wèn)題放在一起說(shuō)了。
其實(shí),關(guān)于字符編碼,我們?cè)谌粘J褂秒娔X是會(huì)經(jīng)常遇到,應(yīng)該說(shuō),我們對(duì)它是不陌生的,舉個(gè)簡(jiǎn)單的例子:
我們?cè)谟?/span>IE瀏覽器訪問(wèn)國(guó)外站點(diǎn)時(shí),經(jīng)常會(huì)出現(xiàn)亂碼,比如在訪問(wèn)一些俄語(yǔ),阿拉伯語(yǔ)等站點(diǎn)時(shí),我們經(jīng)常會(huì)像下圖這樣切換編碼方式以便別看到亂碼:

不多廢話,我們進(jìn)入正題。
林子大了,什么鳥都有,一樣,這個(gè)世界大了,用什么語(yǔ)言的人都有,無(wú)奈,計(jì)算機(jī)是有說(shuō)英語(yǔ)的人發(fā)明的,他們?cè)诳紤]計(jì)算機(jī)里面字符編碼的時(shí)候,只考慮到英語(yǔ)用到的字符,感覺(jué)一些字符占一個(gè)字節(jié)足夠,也沒(méi)有考慮過(guò)像中國(guó),韓國(guó),日本及東南亞等國(guó)的漢字錄入問(wèn)題(感覺(jué)跟90年代時(shí)的千年蟲問(wèn)題歸根同源~),很多的字符都不能正常的在計(jì)算機(jī)中存放,于是便有了Unicode編碼,由于原先多字節(jié)(BYTE為單位)不夠表示這么多的寬字符。
因此,大家就規(guī)定Unicode編碼以(WORD)為單位,存放數(shù)據(jù),這樣每個(gè)字符就大了一倍的空間來(lái)表示字符數(shù)據(jù),表示的范圍也就大了很多,由下面的一個(gè)圖來(lái)說(shuō)明一下他們的區(qū)別吧:

發(fā)現(xiàn)他們的區(qū)別了嗎?中間多了很多的00,就這點(diǎn)區(qū)別,剩下的該是ASCII編碼表轉(zhuǎn)換還是這樣轉(zhuǎn)換的,沒(méi)變!
到這里,或許又有朋友郁悶了,35 00 32 00 中間有0了,結(jié)束了,那字符還怎么能正常的讀啊,這不是沖突嗎?再說(shuō),3500,跟35區(qū)別很大的,怎么都能表示“5”這個(gè)字符 ???
呵呵,按照我們?cè)诒疚拈_(kāi)頭將的內(nèi)存數(shù)據(jù)的存儲(chǔ)方式中Little Endian方式的高高低低原則來(lái)讀取這些字符,以WORD為單位來(lái)轉(zhuǎn)換一下這些數(shù)據(jù),就變成了:0035 0032 0070 …… ,實(shí)質(zhì)上就如同,1與01的區(qū)別一樣,沒(méi)有區(qū)別,唯一的區(qū)別就是表示的范圍大了……
由于在Unicode方式下,原先在多字節(jié)方式下占一個(gè)字節(jié)的字符都變成了占兩個(gè)字節(jié),所以,單純的00 在Unicode方式變成了 00 00 ,自然的,Unicode的字符串都是以 00 00 結(jié)尾的,這下什么就都清楚了吧!
當(dāng)然,如果仔細(xì)想下。Unicode下的普通英文字符中間都被0隔開(kāi)了呀,0是asc編碼下字符串的結(jié)束符啊,電腦是怎么區(qū)別asc和Unicode編碼的呀。由此,就要引出下一個(gè)問(wèn)題:Unicode編碼下的字符數(shù)據(jù)類型。
為了減少篇幅,這里只講述一個(gè)技巧:如果字符類型的關(guān)鍵字中包含‘W’那就差不多應(yīng)該是Unicode編碼的數(shù)據(jù)類型,比如WCHAR, wchar_t等等。(具體內(nèi)容,建議參看:《Windows via C/C++》[Fifth Edition]:Chapter 2: Working with Characters and Strings)
3. 數(shù)據(jù)類型的小結(jié)
數(shù)據(jù)類型:
就是定義數(shù)據(jù)的大小,和數(shù)據(jù)表現(xiàn)形式的一個(gè)規(guī)定,或者說(shuō)一個(gè)模板,根據(jù)這個(gè)模板我們可以生成更多符合這個(gè)模板的數(shù)據(jù)!
一般的,數(shù)據(jù)類型有兩種特性,一個(gè)是它的屬性,一個(gè)是它的方法(也就是動(dòng)作)。
我們拿字符串這個(gè)數(shù)據(jù)類型來(lái)講:
字符串的屬性有:
a) 字符串的大小(有多少個(gè)字符組成)
b) 字符串的結(jié)尾標(biāo)志(0)
字符串的方法(也就是動(dòng)作)有:
a) 將十六進(jìn)制的數(shù)據(jù)轉(zhuǎn)換成字符的形式顯示的控制臺(tái)上.
推而廣之,我們現(xiàn)在所講的什么面向?qū)ο笞兂桑裁搭悾瑢?duì)象的概念,其實(shí)在像C之類面向過(guò)程的編程中已經(jīng)應(yīng)用到了,在C++中只是把這些做了個(gè)升級(jí),讓我們來(lái)做了數(shù)據(jù)類型定義的工作,所謂的類,對(duì)象等其實(shí)就是數(shù)據(jù)類型和變量,換了個(gè)名字而已……
在這里,或許有的朋友不明白,屬性和方法是什么概念,其實(shí)通俗點(diǎn)講,屬性就是變量,方法就是函數(shù),這個(gè)我會(huì)在后面的文章中詳細(xì)講述,由于我們還有學(xué)到編程相關(guān)的知識(shí),這里暫不描述!
下面進(jìn)入我們的下一節(jié),變量的使用。
三、 變量的定義和使用方法
1. 什么是變量。
估計(jì)大家都知道,我們程序訪問(wèn)的數(shù)據(jù)一般的都是存放在內(nèi)存或者寄存器中。自然的,如上次課所講的那些數(shù)據(jù)也都是存放在內(nèi)存中的,那我們?cè)诔绦蛑校绾问褂眠@些內(nèi)存空間呢?這就有了“變量”的概念。如下圖:

這里的00438400就是一個(gè)變量~,如果以一個(gè)字節(jié)的方式來(lái)讀的話,它是一個(gè)BYTE類型的變量,它的內(nèi)容是0xA1,00438401的內(nèi)容就是0xA5,如果以WORD類型來(lái)讀的話,00438400的內(nèi)容是0xA5A1,如果以DWORD類型來(lái)讀的話,00438400的內(nèi)容是0x0000A5A1,想必經(jīng)過(guò)上節(jié)的學(xué)習(xí),我們已經(jīng)能夠理解這些概念了!
那變量的含義也就很清楚了,變量就是內(nèi)存地址。學(xué)過(guò)編程的可能覺(jué)得不理解,編程高手可能就笑我不求甚解了,所以,如果我有什么理解不對(duì)的,不深刻的,還請(qǐng)各位大牛指教!
稍微熟悉點(diǎn)程序的人,應(yīng)該知道,我們的程序被分成了代碼段,數(shù)據(jù)段,資源段,堆棧段等等……
上面我們說(shuō)到過(guò) 變量就是地址,那反過(guò)來(lái)說(shuō),地址就是變量,似乎也是成立的!
比如: 我們的程序代碼是寫在內(nèi)存里的,也就是說(shuō),我們的代碼也可以當(dāng)作變量來(lái)使用!
想想我們寫程序,不就是用代碼通過(guò)變量來(lái)操作數(shù)據(jù)嗎?我們寫的程序本身就是在內(nèi)存里放著的,代碼的每個(gè)字節(jié)都有一個(gè)虛擬地址與它對(duì)應(yīng),也就是說(shuō),我們的代碼本身就是一些數(shù)據(jù)。
從這里來(lái)看,似乎高手們講的什么鉤子,代碼自變形,甚至我們的代碼是可以放在數(shù)據(jù)區(qū)執(zhí)行的等等技術(shù),似乎也不是什么謠不可及的……
想必,大家對(duì)普通的變量應(yīng)該有一定的認(rèn)識(shí)了,這里呢,我就給出變量在C語(yǔ)言中的聲明和表示方法!
2. 變量的定義和使用方法。
在C語(yǔ)言中,我們的變量聲明格式是:
數(shù)據(jù)類型 變量名;
或者
數(shù)據(jù)類型 變量名 = 常量; // 常量就是一個(gè)具體的數(shù)值!
例如:
int x = 2; // 定義了一個(gè)變量x它的內(nèi)容是2
float y = 3.14; // 定義了一個(gè)浮點(diǎn)型變量,內(nèi)容是3.14
在使用這些變量(x,y)時(shí),經(jīng)過(guò)我們上面的定義,x就代表2這個(gè)數(shù)值,y就代表3.14這個(gè)小數(shù),直到我們改變了它的數(shù)值為止。
3. 指針、數(shù)組、結(jié)構(gòu)體
在上一節(jié),我們講數(shù)據(jù)類型的時(shí)候,我們講過(guò)字符串類型,它是一串兒char(byte)類型的序列。如果我們要定義一個(gè)連續(xù)的字符串,那就要用到了數(shù)組的概念。
在C語(yǔ)言中,定義一個(gè)數(shù)組變量的格式如下:
數(shù)據(jù)類型 變量名[元素個(gè)數(shù)];
或者
數(shù)據(jù)類型 變量名[元素個(gè)數(shù)可以留空] = {常量, [常量2|…]}; // 常量就是一個(gè)具體的數(shù)值!
比如:
char addrName[] = “52pojie.cn\0”; // 定義一個(gè)字符數(shù)組,并初始化。
int ntemp[5] = {0,2,4,6,8}; // 定義一個(gè)有個(gè)元素的整型數(shù)組,并初始化。
float fTemp[10]; // 聲明一個(gè)有個(gè)元素的浮點(diǎn)型數(shù)組,沒(méi)初始化。
比如上例中第一個(gè)字符數(shù)組,addrName[0]中的內(nèi)容就是‘5’,addrName[1]中的內(nèi)容就是‘2’,addrName[6]中的內(nèi)容就是’e’了,依次類推!
這個(gè)字符串它在內(nèi)存中的樣子大概如下:

也就是說(shuō),我們的addrName[0]就是內(nèi)存中的地址0x00438AC0,addrName[1]就是內(nèi)存中的地址0x00438AC1;
這里需要說(shuō)明的一點(diǎn),就是,所有的變量名,函數(shù)名,對(duì)象名等等,都是它所代表的內(nèi)存地址的首地址!也就是說(shuō): addrName == addrName[0] == 0x00438AC0;
好了,由于我還沒(méi)有能力寫基礎(chǔ)教程,所以,這里對(duì)C變量相關(guān)的基礎(chǔ)就說(shuō)到這里,再次回到我們的主題:變量就是地址!
如果我們有一個(gè)需求,就是將我們上面聲明的這個(gè)字符串變量輸出出來(lái),那我們的程序需要怎么寫呢?
// test.cpp : Defines the entry point for the application.
//
#include "stdio.h"
#include <windows.h>
char addrName[] = "52pojie.cn\0";
char *szTitle = "Null\0";
// Foward declarations of functions included in this code module:
int main()
{
MessageBoxA(NULL, addrName , szTitle, MB_OK);
return 0;
}
像我們搞破解搞逆向的,一定不會(huì)對(duì)這個(gè)MessageBoxA函數(shù)陌生吧~~,它反匯編的樣子大概是:

相關(guān)內(nèi)存的帖圖:

大家自己根據(jù)我提供的截圖,算一下上面push后面的地址的內(nèi)容想必就應(yīng)該很清楚的發(fā)現(xiàn),我們?cè)诔绦蛑惺褂玫淖兞烤褪侵苯邮褂玫牡刂罚热纾?/span>
00401008 |. 68 30604000 push 00406030 ; |Text = "52pojie.cn"
這里的00406030 就是字符串52pojie.cn的首個(gè)地址,那EAX中的是什么內(nèi)容啊?應(yīng)該也是地址吧~~~?
我們看一下0x0040603C中的內(nèi)容,也就是EAX的內(nèi)容:0x00406040,再看一下0x00406040中的內(nèi)容,很容易的發(fā)現(xiàn),原來(lái)是“Null”,奇特吧~~~
這個(gè)就是我們C語(yǔ)言中說(shuō)到的指針的概念,很多沒(méi)有好好學(xué)C語(yǔ)言的朋友可能都迷糊指針的概念,我們通過(guò)這個(gè)例子就應(yīng)該可以很容易的明白,指針就是存放變量的地址的變量 或者直接說(shuō) 指針就是地址的地址!
指針在C語(yǔ)言中的表示就是*,在匯編語(yǔ)言中的表示就是[],至于為什么要有指針,指針到底有什么作用,在寫程序的過(guò)程中,指針的功能到底應(yīng)該怎么使用,我會(huì)在以后的指針的課題中詳細(xì)介紹!
下面講一下結(jié)構(gòu)體。
如果說(shuō),數(shù)組是一串連續(xù)的相同類型數(shù)據(jù)的序列,那結(jié)構(gòu)體就可以理解為一串連續(xù)的不同類型的數(shù)據(jù)的序列。
在C語(yǔ)言中,定義結(jié)構(gòu)體的語(yǔ)法格式是:
struct 結(jié)構(gòu)體名稱
{
基礎(chǔ)類型1 成員變量名1;
基礎(chǔ)類型2 成員變量名2;
……
}結(jié)構(gòu)體變量名01, 結(jié)構(gòu)體變量名02…;
在實(shí)際使用的過(guò)程中,我們一般用typedef關(guān)鍵字來(lái)定義結(jié)構(gòu)體類型(自定義數(shù)據(jù)類型),然后使用我們自己定義的數(shù)據(jù)類型來(lái)聲明結(jié)構(gòu)體變量,這樣使用起來(lái)更加條例,比如:
typedef struct _GAME_OBJECT_INFO
{
DWORD UnKnown1[15]; // 未知 offset 0
float fX; // X坐標(biāo) offset 0x3C
float fZ; // Z坐標(biāo) offset 0x40
float fY; // Y坐標(biāo) offset 0x44
DWORD UnKnown2[55]; // 未知 offset 0x48
DWORD dwSID; // 怪物ID offset 0x124
DWORD UnKnown3[78]; // 未知 offset 0x128
wchar_t *wszName; // 名字 offset 0x260
}GAME_OBJECT_INFO, *PGAME_OBJECT_INFO;
這樣我們就很容易的定義了兩個(gè)游戲?qū)ο笮畔⒌臄?shù)據(jù)類型,在使用這個(gè)類型來(lái)聲明這個(gè)結(jié)構(gòu)體的變量就很合規(guī)矩了。如下:
GAME_OBJECT_INFO Goi; // 聲明一個(gè)結(jié)構(gòu)體變量
PGAME_OBJECT_INFO pGOI = NULL; // 聲明一個(gè)結(jié)構(gòu)體指針
RtlZeroMemory(pGOI, sizeof(GAME_OBJECT_INFO)); // 給結(jié)構(gòu)體指針初始化。
當(dāng)然,在現(xiàn)在版本的C++中,它支持在結(jié)構(gòu)體中使用函數(shù)(允許結(jié)構(gòu)體中有成員函數(shù)),也就是說(shuō),結(jié)構(gòu)體可以當(dāng)做類來(lái)直接使用,深入的研究結(jié)構(gòu)體可以弄明白現(xiàn)在C++中一些類的基礎(chǔ)概念,為了節(jié)省篇幅,我就不再這里牢騷了。
四、 結(jié)束語(yǔ)
本文講述了很多的東西,很雜,而且?guī)缀醵疾皇呛苌钊耄业谋硎瞿芰τ邢蓿易哉J(rèn)為是用我認(rèn)為最普通的方式,講述這些東西了,肯定還有很多的同學(xué)不明白我講了寫什么,我也深知我沒(méi)有能力講述更基礎(chǔ)的教程了,就寫到這里,希望大家能先看基礎(chǔ)的一些C/C++教程,然后再參考本文,以加深理解,也避免我文中錯(cuò)誤的理解誤導(dǎo)大家。
本文中肯定存在很多的錯(cuò)誤,希望大家能多多指教。