在第十五講里面我們用一個(gè)copy函數(shù)來(lái)結(jié)束,讓大家驗(yàn)證的不知道大家有沒(méi)有驗(yàn)證,這個(gè)函數(shù)從各方面看起來(lái)都總覺(jué)得怪怪的,但是似乎該有的功能卻還是有的,我之所以說(shuō)是似乎,大家不要覺(jué)得奇怪,因?yàn)檫@真的只是似乎。 ----------------------- char* copy(char* dest, const char* src) memset(dest,'\0',sizeof(dest)); while((*dest++ = *src++)!='\0') ; ------------------------------ 這是我們昨天定義的函數(shù),從這幾句代碼里,我們看得出,這個(gè)函數(shù)是有返回值的,返回值就是傳給他的第一個(gè)指針。所以我們?cè)賮?lái)驗(yàn)證一下這個(gè)函數(shù)的返回值。 ------------------------------ char m_array[20] = 'Hello World'; -------------------------------- 大家是不是覺(jué)得m_array3的值和m_array2一樣的呢?為了驗(yàn)明正身,我們不妨將結(jié)果打印出來(lái)看看:
嗯,為什么結(jié)果不和想象中的呢?這不是我們想要的啊,我們想要的是m_array2 = m_array3,為什么會(huì)有這種奇怪的結(jié)果呢?好吧,我們現(xiàn)在再回頭來(lái)研究一下這個(gè)函數(shù)。 現(xiàn)在看來(lái), memset(dest,'\0',sizeof(dest)); 并沒(méi)有起到真正的作用,干脆把他去掉吧。 接下來(lái)我們看到的是拷貝過(guò)程,這個(gè)過(guò)程是通過(guò)while循環(huán)來(lái)控制的呢,直到遇到src的結(jié)尾符'\0'終止,于是我們?cè)谶@里便得到了為什么我們的m_array2能夠得到正確的答案的解釋了。但是接下來(lái)return dest。不過(guò)這時(shí)的dest已經(jīng)不是再最初的那個(gè)dest,也不是我們剛才得到的那個(gè)dest,這個(gè)dest是上面循環(huán)用剩下的,那么要怎么才能實(shí)現(xiàn)返回的和得到的和我們拷貝的是同一個(gè)數(shù)據(jù)呢?這就是我們這里要說(shuō)的指針了。 為什么說(shuō)指針是C/C++的高階知識(shí)呢?為什么會(huì)說(shuō)C++是面對(duì)對(duì)象編程中唯一一門(mén)在內(nèi)存上操作的編程語(yǔ)言?他是怎么實(shí)現(xiàn)在內(nèi)存上操作的呢?這就是我們這里所要說(shuō)的指針,指針就是指向內(nèi)存塊的東東,所以我們要在內(nèi)存上操作,就得依靠指針。指針既然這么重要,那么我們要就來(lái)說(shuō)一下指針。 怎么聲明一個(gè)指針? int* ptr; 就這么簡(jiǎn)單,“*”是指針標(biāo)識(shí)符,聲明一個(gè)指針很簡(jiǎn)單,和聲明一個(gè)數(shù)據(jù)變量沒(méi)有兩樣,唯一的不同點(diǎn)就是在變量前添加這個(gè)”*“,這樣普通變量就變成了該類(lèi)型的指針。 int a = 6; int *ptr = &a; 上面的兩個(gè)聲明,第一句聲明的是一個(gè)變量,第二句是聲明一個(gè)指針,并且讓他指向變量a的地址。 想要取某個(gè)變量的地址,直接在該變量前添加”&“符號(hào)即可,所以對(duì)變量取地址同樣是也相當(dāng)于獲取一個(gè)指針。 大家可以試著用printf('ptr = %p \n.*ptr = %d',ptr,*ptr)看看輸出的是什么結(jié)果。 ptr的值根據(jù)不同系統(tǒng)會(huì)得到不同的值,這就是a所存放的地址,而*ptr卻是這個(gè)地址里面所存放的數(shù)據(jù)6。 說(shuō)到這里,大家是不是想問(wèn),指針和數(shù)組有什么關(guān)系呢?在copy函數(shù)里我們聲明的明明是指針,為什么最后卻又用數(shù)組來(lái)作為參數(shù)呢?這就是現(xiàn)在我們所要說(shuō)的。 上一講我們說(shuō)到數(shù)組是存放在一連串的內(nèi)存之中,那么這段內(nèi)存怎么得到呢?我們是要用像上面那樣取地址表示嗎?當(dāng)然可以,但是沒(méi)有那個(gè)必要,因?yàn)樵跀?shù)組中,數(shù)組名就相當(dāng)于一個(gè)指向這段連續(xù)的首地址的指針,所以我們這就是我們?yōu)槭裁从脭?shù)組名去作為copy函數(shù)的參數(shù)的原因。 在這里給大家說(shuō)一個(gè)關(guān)系式,大家只要記住這個(gè)關(guān)系式就能夠輕松在數(shù)組和指針之間相互轉(zhuǎn)換了: array[i] == *(ptr+i); &array[i] == ptr+i; 這是兩個(gè)恒等式,如果不明白指針和數(shù)組的關(guān)系時(shí)可以再次來(lái)查看這一講。 指針說(shuō)到此處,也差不多了,對(duì)昨天我們的copy函數(shù)現(xiàn)在是不是已經(jīng)明了了呢?既然都明白了,現(xiàn)在我們來(lái)改進(jìn)這個(gè)函數(shù)。我們聲明一個(gè)指針,然后同樣讓他指向dest的地址。 char* get = dest; 在最后我們返回get的地址就好。 return get; ----------------------------- char* copy(char* dest, const char* src) if((dest == NULL) || (src == NULL)) { printf('參數(shù)不能空。'); return NULL; } char* get = dest; -------------------------------- 現(xiàn)在我們同樣用昨天的main()來(lái)調(diào)試這個(gè)函數(shù),發(fā)現(xiàn)沒(méi)問(wèn)題了,m_array2 和 m_array3的結(jié)果相同了,我們多試試幾個(gè)都沒(méi)問(wèn)題,這是不是表示已經(jīng)完美了呢?可以直接代替strcpy()了呢?當(dāng)然能不能我們不知道,但是從我們目前的測(cè)試中可以看出,基本的功能已經(jīng)滿(mǎn)足了,那我們還在懷疑什么呢? 我們?cè)賮?lái)看看這個(gè)函數(shù),他似乎遺漏了一個(gè)問(wèn)題,當(dāng)然這個(gè)問(wèn)題通常都是我們會(huì)回避的,但回避就不代表真正的解決問(wèn)題了,這個(gè)問(wèn)題便是如果這兩個(gè)指針都同時(shí)指向一塊內(nèi)存塊呢?那豈不是糟糕了呢?如同下面一樣: copy(m_array+1,m_array); 當(dāng)我們執(zhí)行這句代碼時(shí),程序崩潰了。我們?cè)谟胹tring.h里面的strcpy來(lái)試試: strcpy(m_array1+1,m_array); 再執(zhí)行程序,發(fā)現(xiàn)毫無(wú)問(wèn)題,既然這個(gè)函數(shù)沒(méi)問(wèn)題,那么有問(wèn)題的就是我們自定義的copy()函數(shù)了, 哎,看來(lái)想要編程真不是一件簡(jiǎn)單的事啊,很多人都以為這是strcpy的偽代碼,但是他們都忽略了一個(gè)問(wèn)題,重復(fù)內(nèi)存的拷貝。 那么怎么實(shí)現(xiàn)重疊內(nèi)存的拷貝呢?我們?cè)賮?lái)定義一個(gè)函數(shù):memcopy(); ------------------------------------ char* memcopy(char* dest,const char* src) { if((dest == NULL) || (src == NULL)) { printf('無(wú)效參數(shù)。'); return NULL; } char* get = dest; int len = strlen(src)+1; if(dest <= src="" ||="" dest="">= (src+len))=> { while(len--) { *dest = *src; dest++; src++; } } else { dest = dest + len -1; src = src + len -1; while(len--) { *dest = *src; dest--; src--; } } return get; } ---------------------------------------------- 然后我們?cè)赾opy里面調(diào)用上面的memcopy函數(shù): ------------------------------ char* copy(char* dest, const char* src) if((dest == NULL) || (src == NULL)) { printf('參數(shù)不能空。'); return NULL; } char* get = dest; return get; ------------------------------------ 這似乎看上去才有些像strcpy()偽碼,但是到底是與不是還得靠大家去驗(yàn)證,因?yàn)榻裉焯砹?,我也沒(méi)驗(yàn)證他的可行性,改天有時(shí)間我親自驗(yàn)證一下是否可行,如果有誤,大家請(qǐng)注意后續(xù)內(nèi)容,一般會(huì)在下一講會(huì)糾正,今天再不推送就浪費(fèi)次數(shù)了。
==================== 回復(fù)D&d直接查看目錄,通知一下,春節(jié)不推送,節(jié)后繼續(xù)。
|
|
來(lái)自: 昵稱(chēng)29398856 > 《第二天》