C語言關於指針的複習整理

一、指針的定義

計算機中所有的數據都必須放在內存中,不同類型的數據佔用的字節數不一樣,例如 int 佔用 4 個字節,char 佔 用 1 個字節。爲了正確地訪問這些數據,必須爲每個字節都編上號碼,就像門牌號、身份證號一樣,每個字節的編 號是唯一的,根據編號可以準確地找到某個字節。

我們將內存中字節的編號稱爲地址(Address)或指針(Pointer)。地址從 0 開始依次增加,對於 32 位環境,程 序能夠使用的內存爲 4GB,最小的地址爲 0,最大的地址爲 0XFFFFFFFF

二、指針變量

1、定義

數據在內存中的地址也稱爲指針,如果一個變量存儲了一份數據的指針,我們就稱它爲指針變量。

int a=1;
int *p;
p=&a;
printf("%d\n", *p); 
printf("%#X, %#X\n", &a, p); 

輸出爲

1  
0X28FF10 , 0X28FF10 

由第一個輸出可以看出,p指向a的地址,利用p可以得到a的取值
%#X 表示以十六進制形式輸出,並附帶前綴 0X,由輸出結果可以看出兩者的到相同的值,證明p爲指針變量,指向並保存a的地址。

2、取址符、解引用符

定義一個指針變量,應該用 *,然後用 **數據類型+***的格式來定義
int *p

由定義可以看出,要想給指針變量賦值,應該用取地址符“&”:
int *p=&a;
1、指針變量也可以連續定義,例如:

  1. int  *a, *b, *c;

a、b、c 的類型都是 int* 注意每個變量前面都要帶*。
2. 如果寫成下面的形式,那麼只有 a 是指針變量,b、c 都是類型爲 int 的普通變量:

   int *a, b, c; 

3、通過指針變量取得數據

int a=1;
int *p;
p=&a;
printf("%d\n", *p); 

輸出a=1。
看起來*p和a是等價的,通過 *p 和 a 獲取到的數據一樣,但它們的運行過程稍有不同:a 只需要一次運算就能夠取得數據,而 *p 要經過兩次 運算,多了一層“間接”。

4、通過指針變量賦值

1 int a=1;
2 int *p=&a;
3 *p=100;
4 printf("%d\n", a); 

輸出 a=100.
第2行代碼中 * 用來指明 p 是一個指針變量,第3 行代碼中 * 用來給指針指向的數據賦值。

三、數組指針

1、定義

數組(Array)是一系列具有相同類型的數據的集合,每一份數據叫做一個數組元素(Element)。數組中的所有元 素在內存中是連續排列的,整個數組佔用的是一塊內存。
如果一個指針指向了數組,我們就稱它爲數組指針(Array Pointer)。

 int arr[] = { 1, 2, 3, 4, 5 }; 
 int *p = arr; 

arr 本身就是一個指針,可以直接賦值給指針變量 p。arr 是數組第 0 個元素的地址,因此不用加 &,
也可以寫作:

 int arr[] = { 1, 2, 3, 4, 5 }; 
 int *p = &arr[0];
 //也可以改變指針指向
 p=&arr[1] ;

arr、p、&arr[0] 這三種寫法都是等價的,它們都指向數組第 0 個元素,或者說指向 數組的開頭。
但是“arr 就是一個指針”這種表述並不準確,嚴格來說應該是“arr 被轉換成了一個指針”。

2、用法

如果一個指針變量 p 指向 了數組的開頭,那麼 p+i 就指向數組的第 i 個元素;如果 p 指向了數組的第 n 個元素,那麼 p+i 就是指向第 n+i 個元素。
要記住數組的下標是從零開始的,如果p開始指向的是arr[0],那麼p+2指向的是arr[2]
由此得出一些利用下標和指針遍歷數組的方法:

  1. 使用下標
    也就是採用 arr[i] 的形式訪問數組元素。如果 p 是指向數組 arr 的指針,那麼也可以使用 p[i] 來訪問數組元素, 它等價於 arr[i]。
  2. 使用指針
    也就是使用 *(p+i) 的形式訪問數組元素。另外數組名本身也是指針,也可以使用 *(arr+i) 來訪問數組元素,它等價 於 *(p+i)。
    如下代碼:
 #include <stdio.h> 

 int main()
 { 
    int arr[] = { 99, 15, 100, 888, 252 }; 
     int *p = &arr[0];  //也可以寫作  int *p = arr+0;
     //第一種方法
     printf("%d, %d, %d, %d, %d\n", *(p), *(p+1), *(p+2), *(p+3), *(p+4) );
     //第二種方法
     for(int i=0;i<5;i++)
     {
        printf("%d",*(a+i));
      }
      //第三種方法
           for(int i=0;i<5;i++)
     {
        printf("%d",*(p+i));
      }
            //第三種方法
       for(int i=0;i<5;i++)
     {
        printf("%d",*(p+i));
      }
      //第四種
       for(int i=0;i<5;i++)
     {
        printf("%d",p[i]);
      }
    return 0; 
  }

3、關於p++ ,++p, (*p)++

*p++ 等價於 *(p++),表示先取得第 n 個元素的值,再將 p 指向下一個元素,即爲將p的地址向後移

*++p 等價於 *(++p),會先進行 ++p 運算,使得 p 的值增加,指向下一個元素,整體上相當於 *(p+1),所以會 獲得第 n+1 個數組元素的值。

(*p)++ 就非常簡單了,會先取得第 n 個元素的值,再對該元素的值加 1。假設 p 指向第 0 個元素,並且第 0 個元素的值爲 99,執行完該語句後,第 0 個元素的值就會變爲 100。

4、字符串數組

字符串數組的用法與數組用法類似:

 #include <stdio.h> 
 #include <string.h> 
   int main()
   {
   char str[] = "hello world";
   char *p = str;
    int len = strlen(str), i; 
  for(i=0; i<len; i++){ 
  printf("%c", *(p+i));
     }    
      printf("\n"); 
         //使用p[i]   
      for(i=0; i<len; i++)
      {
     printf("%c", p[i]); 
       } 
          printf("\n");
          //使用*(str+i) 
     for(i=0; i<len; i++)
     {       
      printf("%c", *(str+i));
     } 
     //使用%s輸出
     printf("%s\n",p);
     printf("\n"); 
        return 0; 
 } 

除了字符數組,C 語言還支持另外一種表示字符串的方法,就是直接使用一個指針指向字符串,例如:
char *str = “hello world”;
或者:
char *str;
str = “hello world”;

四、指針數組

1、定義

如果一個數組中的所有元素保存的都是指針,那麼我們就稱它爲指針數組。
一般形式爲:

int *p[3];

2、用法

1. #include <stdio.h>
2.  int main(){
3.     int a = 1, b = 22, c = 130;
4.      //定義一個指針數組 
5.    int *arr[3] = {&a, &b, &c};//也可以不指定長度,直接寫作 int *arr[] 
6.   printf("%d, %d, %d\n", *arr[0], *arr[1], *arr[2]);
7.  return 0;
8.  } 

arr 是一個指針數組,它包含了 3 個元素,每個元素都是一個指針,在定義 arr 的同時,我們使用變量 a、b、c 的 地址對它進行了初始化,這和普通數組類似。
也可以和字符串結合

9. #include <stdio.h> 
10. int main(){ 
11.      char *str[3] = { 
12.          "afdsf", 
13.         "qtedggew",
14.          "wbfdhdn" 
15.      }; 
16.  printf("%s\n%s\n%s\n", str[0], str[1], str[2]);
17.     return 0; 
18.  } 

五、二級指針

1、定義

1. int a =100; 
2.  int *p1 = &a; 
3.  int **p2 = &p1; 
  1. 指針變量也是一種變量,也會佔用存儲空間,也可以使用&獲取它的地址。
  2. C 語言不限制指針的級數,每增加一級 指針,在定義指針變量時就得增加一個星號*。p1 是一級指針,指向普通類型的數據,定義時有一個*;p2 是二級 指針,指向一級指針 p1,定義時有兩個*。

2、獲取指針數據

想要獲取指針指向的數據時,一級指針加一個*,二級指針加兩個*,三級指針加三個*,以此類推,
如:

1. int a =100; 
2.  int *p1 = &a; 
3.  int **p2 = &p1; 
4. printf("%d,%d\n",*p1,**p2);

六、指針函數和函數指針

1、指針函數

C語言允許函數的返回值是一個指針(地址),我們將這樣的函數稱爲指針函數。
常用代碼形式:

1. #include <stdio.h> 
2.  #include <string.h> 
3.  int *fun1(int x, int y){
4.           x+=y;
5.         return &x;
6.     }
7.  int *fun2(int *x, int* y){
8.      x+=y;
9.  
10.         return x;
11.     }
12. int main(){
13. int m=10,n=20;
14. int *p;
15. p=fun1(m,n);
16. printf("%d\n",*p);
17. p=fun1(&m,&n);
18. printf("%d\n",*p);
19. return 0;
20. }     

用指針作爲函數返回值時需要注意的一點是,函數運行結束後會銷燬在它內部定義的所有局部數據,包括局部變量、 局部數組和形式參數,函數返回的指針請儘量不要指向這些數據, C語言沒有任何機制來保證這些數據會一直有效, 因此在調用完該函數後,應該及時使用運行輸出。

2、函數指針

一個函數總是佔用一段連續的內存區域,函數名在表達式中有時也會被轉換爲該函數所在內存區域的首地址,這和 數組名非常類似。我們可以把函數的這個首地址(或稱入口地址)賦予一個指針變量,使指針變量指向函數所在的 內存區域,然後通過指針變量就可以找到並調用該函數。這種指針就是函數指針。
用法:

1. #include <stdio.h> 
2.  
3.  //返回兩個數中較大的一個 
4.  int max(int a, int b){
5.      return a>b ? a : b; 
6.  } 
7.  int main(){ 
8.      int x, y, num; 
9.     //定義函數指針 
10.     int (*pmax)(int, int) = max;  //也可以寫作int (*pmax)(int a, int b) 
11.   
12.     scanf("%d %d", &x, &y);
13.      num = (*pmax)(x, y); 
14.      printf("Max value: %d\n",num); 
15.     return 0; 
16.  } 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章