作者:driveby
來(lái)源:https://www.cnblogs.com/KKSJS/p/9622812.html
上學(xué)的時(shí)候學(xué)習C語(yǔ)言,最煩的就是里面指針,可是指針也恰恰是C語(yǔ)言的靈魂。
最近在重溫數據結構的內容,因為大多數據結構的教材都是用C語(yǔ)言描述的,而數據結構中也大量的用到了指針的內容,所以我就在這篇筆記中記錄一下我這周復習C語(yǔ)言的心得。
先看看百科上對指針的描述。
在計算機科學(xué)中,指針(Pointer)是編程語(yǔ)言中的一個(gè)對象,利用地址,它的值直接指向(points to)存在計算機存儲器中另一個(gè)地方的值。由于通過(guò)地址能找到所需的變量單元,可以說(shuō),地址指向該變量單元。因此,將地址形象化的稱(chēng)為“指針”。意思是通過(guò)它能找到以它為地址的內存單元。
作個(gè)比喻,假設將計算機存儲器當成一本書(shū),一張內容記錄了某個(gè)頁(yè)碼加上行號的便利貼,可以被當成是一個(gè)指向特定頁(yè)面的指針;根據便利粘貼面的頁(yè)碼與行號,翻到那個(gè)頁(yè)面,把那個(gè)頁(yè)面的那一行文字讀出來(lái),這就是指針的作用。
下面將通過(guò)一些代碼說(shuō)明指針在C語(yǔ)言中的表現形式。
int main(){
int a ;
a = 10;
int *p;
p = &a;
}如果用圖片描述這段代碼,就是下面這個(gè)樣子。
怎么來(lái)理解呢?首先這段代碼里通過(guò)int a和 int *p定義了兩個(gè)變量:分別是p和a,p變量與a變量的定義方式有一些不同,a變量就是C語(yǔ)言中一個(gè)很普通的int型變量,通過(guò)a=10 將10這個(gè)整型賦值給了a。
而p變量的定義前面有一個(gè) * ,這個(gè) * 表明了p變量是一個(gè)指針變量,指針變量里面只能存放地址,這個(gè)地址是內存中的某個(gè)位置,在上面的代碼中我們在p變量里面存放的是0x2C406B24這個(gè)地址,這個(gè)地址里面存放的值必須是int值,在我們這里,p變量里面存放的地址是a變量的地址,a變量在定義時(shí)就是一個(gè)int,所以是符合要求的。
這樣一來(lái),我們就說(shuō)p變量指向了a變量,p = &a 這句代碼完成了p指向a的這個(gè)操作。這里沒(méi)有寫(xiě)p = a,那是因為p變量需要的是一個(gè)地址,而不是a變量里面存放的值,所以&這個(gè)操作符就是取地址的意思,通過(guò)&a取到a變量在內存中的地址,將地址賦值給p指針變量,就使p指向了a。
既然p是一個(gè)指針變量,那它就可以賦值給另外一個(gè)指針變量,如下:
int main(){
int a ;
a = 10;
int *p;
p = &a;
int *q;
q = p;
}新定義了一個(gè)指針變量q,將p變量里的值0x2C406B24這個(gè)地址,賦值給q,這樣q變量與p變量里都保存了同樣的地址,就是說(shuō)他們都指向同一個(gè)值。
int main(){
int a ;
a = 10;
int *p;
p = &a;
int *q;
q = p;
*p = 5; //
*q = 0; //
}介紹完指針,那這個(gè)東西有什么作用呢?如果要修改a變量里面的值,可以執行a=5,這是沒(méi)介紹指針之前的做法。學(xué)習完指針后,通過(guò)指針也能達到修改a變量里的值的目的*p=5。
這是很有用的,舉個(gè)例子,我們來(lái)看下面這段代碼。
void swap(int a,int b);
int main(){
int a = 5;
int b = 6;
swap(a, b);
printf('a=%d b=%d',a,b);
return 0;
}
void swap(int a, int b){
int temp;
temp = a;
a = b;
b = temp;
}上面這段代碼,這段代碼能夠達到交換a和b的值的目的嗎?答案是不能,因為C語(yǔ)言在調用函數時(shí),永遠只能時(shí)傳值給函數。
在C語(yǔ)言中每個(gè)函數都有自己的變量空間,函數的參數也位于這個(gè)獨立的空間中,與其它函數沒(méi)有關(guān)系,上面的代碼中有兩個(gè)函數,一個(gè)是main函數,另一個(gè)是swap函數,所以這兩個(gè)函數里的a,b變量是不同空間中的變量,他們之間毫無(wú)關(guān)系可言。
所以對swap函數中的a,b做交換,完全不能改變main函數中a,b變量的值。
函數在每次運行的時(shí)候,會(huì )產(chǎn)生一個(gè)獨立的變量空間,在這個(gè)空間中的變量,是函數這次調用時(shí)所獨有的,稱(chēng)為本地變量。
定義在函數內部的變量就是本地變量,參數也是本地變量。
變量有 生存期 和 作用域 這兩個(gè)屬性。
生存期:什么時(shí)候變量開(kāi)始出現,到這個(gè)變量消亡
作用域:在代碼的什么范圍內可以訪(fǎng)問(wèn)這個(gè)變量(這個(gè)變量可以起作用)
對于本地變量而言,生存期與作用域都是在本地變量所在的大括號(塊)內。
既然都說(shuō)到本地變量了,那就總結一下本地變量的一些規則。
本地變量的規則:
本地變量定義在塊內
本地變量只存在于運行塊內語(yǔ)句的期間
在塊外面定義的變量,塊里仍然有效
本地變量不會(huì )默認初始化
參數這樣的本地變量在進(jìn)入函數時(shí)就被初始化了
列表內容
又說(shuō)回上面的交換函數,那么怎樣才能達到交換main函數里a,b兩個(gè)變量值的目的呢?
void swap(int a,int b);
int main(){
int a = 5;
int b = 6;
swap(&a, &b);
printf('a=%d b=%d',a,b);
return 0;
}
void swap(int *pa, int *pb){
int temp;
temp = *pa;
*pa = *pb;
*pb = temp;
}利用上面所學(xué)習的指針,改寫(xiě)成上面這樣,才能達到交換的目的。
始終記?。?strong>C語(yǔ)言在調用函數時(shí),永遠只能時(shí)傳值給函數。在上面的代碼中,自然也是傳值進(jìn)的swap函數,只不過(guò)在使用指針時(shí),這個(gè)值指的是地址,地址當然也是一個(gè)值。
將main函數中a和b變量的地址傳給了swap函數中的指針變量pa和pb,在swap函數中通過(guò) *pa 和 *pb 操作到了main函數中的a和b,從而達到了交換的目的。
這只是指針的作用之一,用好了指針,才能體現出C語(yǔ)言更多強大的地方。
這是一篇總結指針的文章,那么我為什么要提到數組呢?
因為數組和指針又太多的相似之處??聪旅嬉欢未a。
int test(int a[], int numOfa){
int i;
for(i = 0; i<numOfa; i ){
printf('%d',a[i])
}
}其實(shí)數組中的[ ],與 * ,. ,& 等運算符一樣,也是一種運算符。
上面test函數里的a數組變量,本身就是一個(gè)地址,所以我們在調用這個(gè)函數的時(shí)候,需要寫(xiě)成這樣test( &a, i) ,需要傳入一個(gè)地址,這個(gè)地址所在的變量保存的就是一個(gè)數組。
例如:
int a[10]; int *p = a; // 不需要用&取地址,數組變量本身就表達地址
a == &a[0] 但是數組的單元表示的是變量,需要用&對變量取地址。數組變量第一個(gè)單元的地址就是數組變量的地址。
p[0] == a[0] [ ] 運算符可以對數組做,也可以對指針做
*a = 9 將數組的第一個(gè)單元賦值為9,說(shuō)明 * 運算符既可以對數組做,也可以對指針做
最后在總結一下const關(guān)鍵字在指針中的規則:
const int *p = &i :const在前,表示不能通過(guò)指針去修改變量
int * const p = &i :const在后,表示p這個(gè)指針變量不能再保存別的地址值
聯(lián)系客服