第四十八章 指針(三)
「那swap里面的int temp =*x和下面的操作是什么意思?。俊?p> 「這里就涉及到了指針中最常用的兩個運算符了:*和&。
取地址符&算是我們的老朋友了,它能夠?qū)⒁粋€變量藏在靈魂深處地址取出來。在我們最初使用scanf函數(shù)的時候,就用到了它,例如我們要從小黑屏上面輸入一個數(shù)字,然后把這個數(shù)字賦值給a:
int a = 0;
scanf(“%d“,&a);
現(xiàn)在我們學了指針了,其實這兩句代碼和下面的代碼起到過效果完全一樣:
int a = 0;
int* p =&a;
scanf(“%d“, p);
在上面的代碼中,咱們把a的地址取出來了,然后把這個地址賦值給了一個指向int類型的指針變量p,在scanf函數(shù)中,實際上就通過這個指針變量p給a進行了賦值。
至于*嘛,它可是&的好伙伴,&能夠?qū)⒁粋€變量的地址取出來,*可以從這個地址中獲取變量的值,它們倆加起來可以說的狼狽為奸,無惡不作,沒有哪個變量能夠逃出它們的手掌心。
用另外一個方式說,這兩貨就是那種游戲中開掛的,能力強得一塌糊涂。
我們還是拿可憐的變量a來舉例子:
int a = 0;
int* p =&a;
*p = 10;
這個時候*p就相當于a本身了,也就是說,我們可以通過*p來操作變量a所在那四個字節(jié)內(nèi)存。我們對*p進行賦值,效果和對a賦值一樣,而我們把*p賦值給一個變量,就和把a賦值給一個變量效果一樣。例如:
int b =*p;
和
int b = a;
效果完全一樣?!?p> 「那這么看來指針的使用也不是那么難嘛,就這么兩個運算符?!?p> 從老爹目前的講述來看,指針真的沒有什么難的,無非就是通過利用指針地址給某個變量賦值,或者獲取某個變量的值。只是讓我想不明白的是,明明我們已經(jīng)有了變量名,為什么還要設(shè)計指針這種東西?
等等,我似乎明白老爹那個swap函數(shù)的原理了。
「老爹,我好像明白那個用指針實現(xiàn)a、b兩個變量內(nèi)容交換的原理了。」
我腦中劃過一道電光,整個人猶如醍醐灌頂,想明白了一切。
「哦,說說看!」
老爹饒有趣味地看著我。
「指針變量,指針變量,首先它是一個變量,那么指針變量在函數(shù)中傳參的時候肯定也要遵守和普通變量一樣的規(guī)則——值傳遞!
swap函數(shù)之所以能夠?qū)崿F(xiàn)交換兩個交換,是因為指針變量傳遞的值不是普通的值,而是一個地址。
按照老爹你之前的說法,在調(diào)用函數(shù)時,將會把實際參數(shù)的值復制一份給形式參數(shù),所以形式參數(shù)同樣也拿到了要進行交換的那兩個變量的地址,那么我們通過地址進行讀寫操作最后同樣會作用在變量上!」
「啪……啪……啪……不錯不錯,居然一下子就明白這其中的原理所在!想當年我領(lǐng)悟到這一層的時候可是花了不少的時間!」
老爹一臉拍了十來下手掌,毫不吝惜他的贊揚之詞。
就連旁邊的小弦子也面露佩服之色,看來我總算是贏了小弦子一次了!
「不錯,這就是指針存在的意義所在。而且指針之所以說它是C語言的精髓所在,并不是說它的用法有多么復雜,而是它可以和任意數(shù)據(jù)類型結(jié)合在一起,非常的靈活。
但是它也有讓人抓狂的時候,一旦指針出問題,可能讓你抓破腦袋也想不明白問題出在哪兒。放心,以后你們都會遇到的。」
老爹神秘地笑了笑。
「現(xiàn)在的內(nèi)容還能聽懂么?」
「嗯~」
「好,能聽懂的話我們就進行下部分內(nèi)容——指針和數(shù)組的結(jié)合使用,睜大你們的眼睛看清楚了:
int a[]={1, 2, 3, 4, 5};
int *p = a;
看到?jīng)],我現(xiàn)在把一個int數(shù)組賦值給了一個指向int類型的指針,你們大膽地猜測一下會不會出錯?」
「呵呵,我才懶得猜,把代碼寫出來編譯一下不就知道會不會出錯了么?」
我都被自己的機智感動了,當然了,這是因為我有所依仗。這一來嘛,區(qū)區(qū)兩句代碼而已,二來就是我打字速度快??!
一頓操作猛如虎,編寫、編譯分分鐘搞定。
「咦,還真的可以??!」
「所以啊,記住,一個數(shù)組的數(shù)組名,就是這個數(shù)組的指針地址,也是數(shù)組首個元素的地址,換言之,上面的代碼這句等效:
int* p =&a[0];
既然我們都已經(jīng)拿到一個數(shù)組的指針地址了,那么接下來就可以對它的元素進行任意讀寫操作了。不過有一點要記住,一定不能超過數(shù)組的上下限,不然你就死翹翹!
我們可以利用指針來獲取元素,或者給元素賦值:
for(int i = 0; i < 5; i++)
{
printf(“%d,%d,%d“,a[i], p[i],*(p + i));
}
來來來,猜猜結(jié)果,猜中了有獎勵哦!」
「哈哈,它們輸出的內(nèi)容是相同的!」
老爹話音剛落,我這邊就已經(jīng)看到了運行結(jié)果。
「嘿,任靈玥同學,你這么喜歡敲代碼是吧,信不信我讓你手寫50遍!」
老爹做出一副很兇的樣子說道。
「沒錯,它們輸出的內(nèi)容的確是相同的,那是因為它們的作用一模一樣。剛剛我說了,數(shù)組名就是一個數(shù)組的指針地址,既然可以用a[i]來獲取元素值,我們把a賦值給了p,那么p當然也是可以這樣操作的。
至于p + 1嘛,是將指針指向的位置往從前位置移動一個單位。注意,這里的單位就和指針的指向的數(shù)據(jù)類型有關(guān)系了,如果指針指向的數(shù)據(jù)類型是一個int,那么它指向的就是下一個int數(shù)據(jù),是double的話,就移動到下一個double數(shù)據(jù)。
換句話說,*(p + i)等效于p =(int*)((int)p + i * 4)。
我們首先把p的值,也就是一個地址值轉(zhuǎn)換成int類型,假設(shè)數(shù)組a在內(nèi)存中的地址是1234,p + i其實就是執(zhí)行了1234 + i * 4,然后再把這個值,那么*(p + i)自然就是取的起始地址為1234 + i * 4這個int數(shù)據(jù)的值了。
而a[0]的地址是1234;
a[1」的地址是1234 + 1 * 4;
a[2」的地址是1234 + 2 * 4;
a[3」的地址是1234 + 3 * 4;
a[4」的地址是1234 + 4 * 4;