指針是c語言的一個特色。
1 將地址形象的比喻為指針。
2 訪問的兩種形式:1 直接訪問:比如定義了變量a,然后通過變量名a直接訪問
2 間接訪問:定義a,得知a的地址,由於地址指向變量,所以可以直接 訪問。
3 除了整型,實型,字符型,還有一種是存放地址的變量。Int * a;a= &p;
4 一個變量的地址我們稱之為指針;一個存放別的變量地址的變量叫做指針變量;指針變量的值就是指針(即地址);如果存放的指針指向的數據是整形,則我們說這個指針變量是指向整形變量的指針變量。
<重中之重>指針變量:1 程序中兩處 * :聲明與使用。
聲明: * 指示后面的變量是指針變量,且其基類型是前面的類型。
使用: * 運算符,把地址轉向所指向的變量。
2可以在定義時同時對他進行初始化。
3 必須指定基類型:因為他指代的數據類型有可能是int long 等等,而在后續要進行指針的加減,指針加一,如果是int 則增加2或4個字節,如果是long,則8個字節。所以一定要指定。
4 賦給指針的變量一定是地址,而不能是其他數據類型。
5 給指針變量賦值:1直接賦值 p=&a;
2 引用賦值 如果*p=1;之前必須p=&a;否則會因為不知道地址而有可能會占用有用的地址。
6 注意指針變量也是一個變量,所以在指針變量的范疇內,各種變量的賦值都可以,就和變量一樣,而和普通變量交互,則需要有地址,有基變量。
<第一個重點>
重重重重:1 單向的值傳遞:即實參傳遞過去的形參,之后是形參來回變換,與實參無關。2 由於地址本身就存在,不存在什么變化,所以,只能夠通過地址指向的值來回改變。
指針可以作為函數參數
要點:1(單向的值傳遞) 所有都要與之結合。
要點:2(址變換) 3(*址變換) 4(值變換)只有4不可以改變原值
重點:不可能通過調用函數來改變實參指針變量的值,但是可以實參指針變量所指向的值。
函數的參數不僅可以是整形,實數型,字符型,數組型,也可以是指針型。
他的目的是址傳遞。
<A>我們的問題是如何使原值改變。函數參數傳值,傳完之后回來,看是否原值改變。
以兩個數要變換為例。
首先采用(值傳遞),由於是單向傳遞,況且要想改變原數據,必須要從指針(地址)這方面下手,所以,即不可以改變原值;
然后是(址傳遞),由於傳過來之后,實參要賦給形參,而此時在變換函數(swap)形參來回變換,也就是實參不變換,而形參變換,所以沒用,且是單向的。所以不能改變原值。
然后是(*地址)傳遞,自己畫圖,實參傳過來之后,由於雖然還是改變形參,但是改變的是形參上對應的數字,即改變原地址上對應的數字,即可以改變原值。
<誤區> 就是說以前雖然是值傳遞,但是值傳遞回來return之后賦給了新的變量,既然是新的變量,所以輸出了之后肯定是改變數據的,這就是產生錯覺的原因。
總結難點:1 單向的值傳遞:即實參傳遞過去的形參,之后是形參來回變換,與實參無關。2 由於地址本身就存在,不存在什么變化,所以,只能夠通過地址指向的值來回改變。
<第二個重點>:通過指針引用數組。
1 數組元素的指針就是數組元素的地址。
2 引用數組可以用下表法,也可以用指針法。
重:3 數組名(不包括形參的數組名)可以與首元素地址等價。即 int * p;p=a或p=&a[0];
重:4 指針法 *(a+i) *(p+i);這兩者都是指向a[i];
5 指針運算:
1 首先指針運算的p++不是簡單地加一,而是根據變量類型的字節數去加一。如果是int 則可能是+2 或+4,如果是float,則是+4;
2 可以使用p++,因為他是變量,而不能使用a++,因為a是常量。
重:注意p+i與a+i的區別,a+i是自身的地址直接加字節數,而p+i是把地址賦給另一個指針變量去進行加減。
6 寫程序時要注意此時指針的位置,因為就算超出,他實際上也不會報錯。
7 也可以使用p[i],但是注意此時一定要知道當前p在什么位置,如果一開始P指向a[2],則p[3]則是a[5],所以不建議使用這種方式.
8 <重中之重>:用數組名做函數參數:
1 形參數組的值發生變化,實參也發生變化(注意:形參的值指的是指針的值而不是地址【上一節指針做參數的三種情況】)
重:2 void f(int arr[],int n)=====等價於void f(int * arr,int n);
3 指針變量在visual c++里占據4個字節。
4 實參數組名是一個常量,而形參數組名是一個變量,所以可以賦值,而常量不可以賦值即a=a+3(a是常量),不能使用,而(arr=arr+3)是可以的;
<第三個重點>:通過指針引用字符串
1 表示字符串的兩種方法:1 用字符數組2 用指針指向字符串的字符。
2 指針法:char * string=”I love china”; printf(“%s”,string);
3 不能夠重新賦值,因為字符常量是不能改變的。
重:4 實際上是把字符串的第一個字符的地址賦給指針變量,然后輸出會自加(這就是不用遍歷的原因),最后遇到\0會停止(這才是可以自加的真正原因吧,因為可以自動停止)。
重:5 為什么輸出地址就可以輸出字符?數組就需要*?
應該是編譯器的處理,因為字符數組即char a[]遍歷就需要*a.
6 輸出的時候還是用字符數組。
<重中之重>:
1 傳遞參數可以用數組名,即地址,也可以用指針。
重:2 字符數組除了比數字數組多了一種方法,首先他倆同時都可以傳遞數組名和數組首地址,當然首地址是用另一個變量,並且由於他還可以這么定義char * string=”i love china”;所以還可以直接把string傳遞,其實本質是一樣的,都是地址,只不過編譯器對他進行了優化(遍歷,不用加*),所以其實都是一樣的。
實參形參的數組名與指針?
3 最后要自己加上\0;
4 最后就是寫法問題???
重:5作為實參,可以用數組名(不帶中括號),可以用char * p(其中p=a或&a[0]),即變量;還可以用char * string=”aaaaaa”,直接把string傳入。當然,前兩種就是和數字數組是一樣的。即字符數組和數字數組基本上是一樣的,只不過多了一種寫法。
作為形參,本可以用數組名和指針變量,但是不知道為啥數組名行不通,暫且就是指針變量把。
6 字符數組可以再賦值,字符指針變量不可以。
重重重重:都是地址(基本上是一個,數組則是首地址)的傳入傳出,所以可以對原值改變。
重重重重:當想改變原值的時候,比如int a;在改變值的函數內部,一定要賦值,
舉個例子:#include<stdio.h>
int main(){
void change(int * m);
int a=10;
int *p;
p=&a;
change(p);
printf("%d",a);
return 0;
}
void change(int * m){
* m=* m+1;//注:這里一定要給*m賦值,之前的錯誤是只有*m+1,而沒有賦值,結果當然不會改變。
}
重重重重:字符型實參傳遞參數的形式:1 數組名 2 數組首地址 3 string 注:前兩種形式都是字符數組,最后一種是指針型字符數組。
字符型形參應該是 1 * ,2 m[]注:兩種都行,但是現在給第一種賦值遇到一些問題。
附代碼:#include<stdio.h>
int main()
{
void change(char * m);
char * string="Ia love China";
char a[19]="I love china";
//change(&a[0]);
change(string);
//傳遞參數的形式:1 數組名 2 數組首地址 3 string 注:前兩種形式都是字符數組,最后一種是指針型字符數組
//change(string);
printf("%s\n",a);
return 0;
}
void change(char * m){
//形參應該是 1 * ,2 m[]注:兩種都行,但是現在給第一種賦值遇到一些問題。
*m='u';//這里現在遇到一些問題。
}