C語言指針詳解

指針

我們通過指針,可以簡化一些 C 編程任務的執行,還有一些任務,如動態內存分配,沒有指針是無法執行的。所以,學習指針是很有必要的。 
正如您所知道的,每一個變量都有一個內存位置,每一個內存位置都定義了可使用連字號(&)運算符訪問的地址,它表示了在內存中的一個地址。請看下面的實例,它將輸出定義的變量地址:

#include <stdio.h>

int main ()
{
   int  var1;
   char var2[10];

   printf("var1 變量的地址: %x\n", &var1  );
   printf("var2 變量的地址: %x\n", &var2  );

   return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

當上面的代碼被編譯和執行時,它會產生下列結果:

var1 變量的地址: bff5a400
var2 變量的地址: bff5a3f6
  • 1
  • 2
  • 1
  • 2

通過上面的栗子,我們瞭解了什麼是內存地址以及如何訪問它。接下來讓我們看看什麼是指針吧!

什麼是指針?

指針是一個變量,其值爲另一個變量的地址,即內存位置的直接地址。就像其他變量或常量一樣,您必須在使用指針存儲其他變量地址之前,對其進行聲明。指針變量聲明的一般形式爲:

type *name;
  • 1
  • 1

這裏的type 是指針的基類型,它必須是一個有效的 C 數據類型,name 是指針變量的名稱。用來聲明指針的星號 * 與乘法中使用的星號是相同的。但是,在這個語句中,星號是用來指定一個變量是指針。以下是有效的指針聲明:

int    *ip;    /* 一個整型的指針 */
double *dp;    /* 一個 double 型的指針 */
float  *fp;    /* 一個浮點型的指針 */
char   *ch     /* 一個字符型的指針 */
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

所有指針的值的實際數據類型,不管是整型、浮點型、字符型,還是其他的數據類型,都是一樣的,都是一個代表內存地址的長的十六進制數。不同數據類型的指針之間唯一的不同是,指針所指向的變量或常量的數據類型不同。

如何使用指針?

  • 使用指針時會頻繁進行以下幾個操作:定義一個指針變量、把變量地址賦值給指針、訪問指針變量中可用地址的值。這些是通過使用一元運算符 * 來返回位於操作數所指定地址的變量的值。下面的實例涉及到了這些操作:
#include <stdio.h>
//指針
//指針存儲的是變量的內存地址
//內存地址,系統給數據分配的編號(門牌號)

void main(){
    int i = 90;
    //指針變量,創建一個int類型的指針
    int* p = &i; //p的值就是i這個變量的內存地址
    printf("%#x\n",p);

    float f = 89.5f;
    //創建一個float類型的指針
    float *fp = &f;
    printf("%#x\n", fp);

    system("pause");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

上面的代碼被編譯和執行時,運行的結果:

0xeffb30
0xeffb18
請按任意鍵繼續. . .
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
  • 對指針存的地址指向的變量進行操作
#include <stdio.h>

void change(int* p){
    *p = 300;
}

//變量名,對內存空間上的一段數據的抽象
void main(){
    int i = 90;
    //i = 89;
    //創建一個int類型的指針
    int *p = &i;
    //輸出地址
    printf("p的地址:%#x\n",&p);
    printf("i的地址:%#x\n",&i);
    printf("i的值爲:%d\n", i);
    //間接賦值 i = 200;

    //對p存的地址指向的變量進行操作
    //*p = 200;
    //change(p);
    change(&i);  // int *p = &i;
    printf("i的值爲:%d\n",i);

    system("pause");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

上面代碼編譯執行結果如下:

p的地址:0x6ffdb0
i的地址:0x6ffdbc
i的值爲:90
i的值爲:300
請按任意鍵繼續. . .
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

通過上面栗子,我們可以看出,指針所指向的變量值已經被更改了。

C中的NULL 指針

在變量聲明的時候,如果沒有確切的地址可以賦值,爲指針變量賦一個 NULL 值是一個良好的編程習慣。賦爲 NULL 值的指針被稱爲空指針。 
NULL 指針是一個定義在標準庫中的值爲零的常量。請看下面的程序:

#include <stdio.h>

int main ()
{
   int  *ptr = NULL;

   printf("ptr 的值是 %x\n", ptr  );

   return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

運行結果爲:

ptr 的值是 0
  • 1
  • 1

在大多數的操作系統上,程序不允許訪問地址爲 0 的內存,因爲該內存是操作系統保留的。然而,內存地址 0 有特別重要的意義,它表明該指針不指向一個可訪問的內存位置。但按照慣例,如果指針包含空值(零值),則假定它不指向任何東西。 
如需檢查一個空指針,您可以使用 if 語句,如下所示:

#include <stdio.h>

int main(int argc, char const *argv[]) {

  char *s = "hello";

  if (!s) {
    fprintf(stderr, "s is null\n");
  } else {
    fprintf(stderr, "%s\n", s);
  }

  if (s == NULL) {
    fprintf(stderr, "s is null\n");
  } else {
    fprintf(stderr, "%s\n", s);
  }


  return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

這兩種方法都能判斷字符指針是否爲空,但推薦使用前者。”NULL” 的本質是個宏,並非是個常量,C99 中甚至可以自行定義,故儘量避免使用它去判斷,當 !s 與 s == NULL 表示同一含義的時候,使用前者吧!

C中的二級指針(多級指針)

指針可以指向一份普通類型的數據,例如 int、double、char 等,也可以指向一份指針類型的數據,例如 int 、double 、char * 等。

如果一個指針指向的是另外一個指針,我們就稱它爲二級指針,或者指向指針的指針。 
假設有一個 int 類型的變量 a,p1是指向 a 的指針變量,p2 又是指向 p1 的指針變量,它們的關係如下圖所示:

這裏寫圖片描述

用代碼表示爲:

int a =100;
int *p1 = &a;
int **p2 = &p1;
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

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

如果再定義一個三級指針 p3,讓它指向 p2,那麼可以這樣寫:

int ***p3 = &p2;
  • 1
  • 1

四級指針:

int ****p4 = &p3;
  • 1
  • 1

等等,以此類推。。。 
不過,經常使用的也就是一級指針和二級指針了。 
在獲取指針指向的數據時,一級指針加一個 * ,二級指針加兩個 * ,三級指針加三個 *,以此類推,請看代碼:

#include <stdio.h>
int main(){
    int a =100;
    int *p1 = &a;
    int **p2 = &p1;
    int ***p3 = &p2;
    printf("%d, %d, %d, %d\n", a, *p1, **p2, ***p3);
    printf("&p2 = %#X, p3 = %#X\n", &p2, p3);
    printf("&p1 = %#X, p2 = %#X, *p3 = %#X\n", &p1, p2, *p3);
    printf(" &a = %#X, p1 = %#X, *p2 = %#X, **p3 = %#X\n", &a, p1, *p2, **p3);
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

編譯並運行結果如下: 
這裏寫圖片描述

以三級指針 p3 爲例來分析上面的代碼。* p3等價於 * ( * (* p3))。* p3 得到的是 p2 的值,也即 p1 的地址;* ( * p3) 得到的是 p1 的值,也即 a 的地址;經過三次“取值”操作後,* ( *(p3)) 得到的纔是 a 的值。

假設 a、p1、p2、p3 的地址分別是 0X00A0、0X1000、0X2000、0X3000,它們之間的關係可以用下圖來描述:

這裏寫圖片描述

方框裏面是變量本身的值,方框下面是變量的地址。

C中指針的運算

指針變量保存的是地址,本質上是一個整數,可以進行部分運算,例如加法、減法、比較等,請看下面的代碼:


#include <stdio.h>
//指針的運算,一般在數組遍歷時纔有意義,基於數組在內存中線性排列的方式
void main(){
    //數組在內存中連續存儲
    int ids[] = { 78, 90, 23, 65, 19 };
    //數組變量名:ids就是數組的首地址
    printf("%#x\n",ids);
    printf("%#x\n",&ids);
    printf("%#x\n",&ids[0]);
    //指針變量
    int *p = ids;
    printf("%d\n",*p);
    //指針的加法
    p++; //p++向前移動sizeof(數據類型)個字節
    printf("p的值:%#x\n", p);
    //p--;
    printf("%d\n", *p);
    getchar();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

編譯並運行的結果如下:

0x5ff7d0
0x5ff7d0
0x5ff7d0
78
p的值:0x5ff7d4
90
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

從上面的栗子來看,數組變量名:ids就是數組的首地址,指針的加法,p++就是向前移動了sizeof(數據類型)個字節。 
我們知道,數組中的所有元素在內存中是連續排列的,如果一個指針指向了數組中的某個元素,那麼加 1 就表示指向下一個元素,減 1 就表示指向上一個元素,不過C語言並沒有規定變量的存儲方式,如果連續定義多個變量,它們有可能是挨着的,也有可能是分散的,這取決於變量的類型、編譯器的實現以及具體的編譯模式,所以對於指向普通變量的指針,我們往往不進行加減運算,雖然編譯器並不會報錯,但這樣做沒有意義,因爲不知道它後面指向的是什麼數據。

下面舉一個栗子,通過指針獲取下一個變量的地址:

#include <stdio.h>
int main(){
    int a = 1, b = 2, c = 3;
    int *p = &c;
    int i;
    for(i=0; i<8; i++){
        printf("%d, ", *(p+i) );
    }
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

編譯並運行結果如下:

3, -858993460, -858993460, 2, -858993460, -858993460, 1, -858993460,
  • 1
  • 1

可以看出變量 a、b、c 並不挨着,它們中間還有其他的數據。

指針變量除了可以參與加減運算,還可以參與比較運算。當對指針變量進行比較運算時,比較的是指針變量本身的值,也就是數據的地址。如果地址相等,那麼兩個指針就指向同一份數據,否則就指向不同的數據。 
所以總結出,不要對指向普通變量的指針進行加減運算;另外需要說明的是,不能對指針變量進行乘法、除法、取餘等其他運算,除了會發生語法錯誤,也沒有實際的含義。

C中的指針數組

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

dataType *arrayName[length];
  • 1
  • 1

]的優先級高於*,該定義形式應該理解爲:

dataType *(arrayName[length]);
  • 1
  • 1

括號裏面說明arrayName是一個數組,包含了length個元素,括號外面說明每個元素的類型爲dataType *。

除了每個元素的數據類型不同,指針數組和普通數組在其他方面都是一樣的,下面是一個簡單的栗子:

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

編譯並運行結果如下:

16, 932, 100
16, 932, 100
  • 1
  • 2
  • 1
  • 2

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

parr 是指向數組 arr 的指針,確切地說是指向 arr 第一個元素的指針,它的定義形式應該理解爲int * ( * parr),括號中的 * 表示 parr 是一個指針,括號外面的int * 表示 parr 指向的數據的類型。arr 第一個元素的類型爲 int *, 
所以在定義 parr 時要加兩個 * (星號)(MD語法自動識別其他的格式了)。

第一個 printf() 語句中,arr[i] 表示獲取第 i 個元素的值,該元素是一個指針,還需要在前面增加一個 * 才能取得它指向的數據,也即 *arr[i] 的形式。

第二個 printf() 語句中,parr+i 表示第 i 個元素的地址,* (parr+i) 表示獲取第 i 個元素的值(該元素是一個指針),**(parr+i) 表示獲取第 i 個元素指向的數據。

通過指針給數組賦值,下面是一個簡單的栗子:

#include <stdio.h>
void main(){
    int uids[5];
    //高級寫法
    //int i = 0;
    //for (; i < 5; i++){
    //  uids[i] = i;
    //}
    //早些版本的寫法
    int* p = uids;
    printf("%#x\n",p);
    int i = 0; //i是數組元素的值
    for (; p < uids + 5; p++){
        *p = i;
        i++;
    }

    getchar();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

C中的指針與二維數組

二維數組在概念上是二維的,有行和列,但在內存中所有的數組元素都是連續排列的,它們之間沒有“縫隙”。以下面的二維數組 a 爲例:

int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };
  • 1
  • 1

從概念上來理解,數組a 的分佈如下:

0   1   2   3
4   5   6   7
8   9  10  11
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

但在內存中,a 的分佈是一維線性的,整個數組佔用一塊連續的內存:

這裏寫圖片描述

C語言中的二維數組是按行排列的,也就是先存放 a[0] 行,再存放 a[1] 行,最後存放 a[2] 行;每行中的 4 個元素也是依次存放。數組 a 爲 int 類型,每個元素佔用 4 個字節,整個數組共佔用 4×(3×4) = 48 個字節。

C語言允許把一個二維數組分解成多個一維數組來處理。對於數組 a,它可以分解成三個一維數組,即 a[0]、a[1]、a[2]。每一個一維數組又包含了 4 個元素,例如 a[0] 包含 a[0][0]、a[0][1]、a[0][2]、a[0][3]。

假設數組 a 中第 0 個元素的地址爲 1000,那麼每個一維數組的首地址如下圖所示: 
這裏寫圖片描述

爲了更好的理解指針和二維數組的關係,我們先來定義一個指向 a 的指針變量 p:

int (*p)[4] = a;
  • 1
  • 1

int *p[4]; //定義一個指針數組,該數組中每個元素是一個指針,每個指針指向哪裏就需要程序中後續再定義了。

int (*p)[4]; //定義一個數組指針,該指針指向含4個元素的一維數組(數組中每個元素是int型)。

區分int *p[n]; 和int (*p)[n]; 就要看運算符的優先級了。
int *p[n]; 中,運算符[ ]優先級高,先與p結合成爲一個數組,再由int*說明這是一個整型指針數組。
int (*p)[n]; 中( )優先級高,首先說明p是一個指針,指向一個整型的一維數組。
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

對指針進行加法(減法)運算時,它前進(後退)的步長與它指向的數據類型有關,p 指向的數據類型是int [4],那麼p+1就前進 4×4 = 16 個字節,p-1就後退 16 個字節,這正好是數組 a 所包含的每個一維數組的長度。也就是說,p+1會使得指針指向二維數組的下一行,p-1會使得指針指向數組的上一行。

下面我們就來實現如何使用指針 p 來訪問二維數組中的每個元素。按照上面的定義:

  • p指向數組 a 的開頭,也即第 0 行;p+1前進一行,指向第 1 行。
  • *(p+1)表示取地址上的數據,也就是整個第 1 行數據。注意是一行數據,是多個數據,不是第 1 行中的第 0 個元素,下面的運行結果有力地證明了這一點:
#include <stdio.h>
int main(){
    int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };
    int (*p)[4] = a;
    printf("%d\n", sizeof(*(p+1)));
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

編譯並運行結果爲:

16
  • 1
  • 1

那麼,*(p+1)+1表示第 1 行第 1 個元素的地址。這個如何理解呢?(注意,這裏的小細節)

  *(p+1)單獨使用時表示的是第 1 行數據,放在表達式中會被轉換爲第 1 行數據的首地址,也就是第 1 行第 0 個元素的地址,因爲使用整行數據沒有實際的含義,編譯器遇到這種情況都會轉換爲指向該行第 0 個元素的指針;就像一維數組的名字,在定義時或者和 sizeof、& 一起使用時才表示整個數組,出現在表達式中就會被轉換爲指向數組第 0 個元素的指針。
  • 1
  • 2
  • 1
  • 2
* ( *(p+1)+1) 表示第 1 行第 1 個元素的值。很明顯,增加一個 * 表示取地址上的數據。
  • 1
  • 1

根據上面的推論,推出以下等價關係:

a+i == p+i
a[i] == p[i] == *(a+i) == *(p+i)
a[i][j] == p[i][j] == *(a[i]+j) == *(p[i]+j) == *(*(a+i)+j) == *(*(p+i)+j)
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

可能有點繞,不好理解,不過沒關係,多看幾遍,相信你是可以的。

栗子: 
使用指針遍歷二維數組

#include <stdio.h>
int main(){
    int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
    int(*p)[4];
    int i,j;
    p=a;
    for(i=0; i<3; i++){
        for(j=0; j<4; j++) printf("%2d  ",*(*(p+i)+j));
        printf("\n");
    }
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

編譯並運行的結果如下:

 0   1   2   3
 4   5   6   7
 8   9  10  11
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

指針數組和二維數組指針的區別:

指針數組和二維數組指針在定義時非常相似,只是括號的位置不同:

int *(p1[5]);  //指針數組,可以去掉括號直接寫作 int *p1[5];
int (*p2)[5];  //二維數組指針,不能去掉括號
  • 1
  • 2
  • 1
  • 2

指針數組和二維數組指針有着本質上的區別:指針數組是一個數組,只是每個元素保存的都是指針,以上面的 p1 爲例,在32位環境下它佔用 4×5 = 20 個字節的內存。二維數組指針是一個指針,它指向一個二維數組,以上面的 p2 爲例,它佔用 4 個字節的內存。

C中的函數指針

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

函數指針的定義形式爲:

returnType (*pointerName)(param list);
  • 1
  • 1

returnType 爲函數返回值類型,pointerNmae 爲指針名稱,param list 爲函數參數列表。

注意:

( )的優先級高於*,第一個括號不能省略,如果寫作returnType *pointerName(paramlist); 
就成了函數原型,它表明函數的返回值類型爲returnType *。

下面寫一個簡單的栗子:

#include <stdio.h>
#include <Windows.h>

int msg(char* msg,char* title){
    MessageBox(0,msg,title,0);
    return 0;
}
void main(){
    //msg();
    printf("%#x\n",msg);
    printf("%#x\n",&msg);
    //函數指針
    //函數返回值類型,函數指針的名稱,函數的參數列表
    int(*fun_p)(char* msg, char* title) = msg;
    fun_p("消息內容","標題");

    getchar();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

編譯並運行結果如下:

這裏寫圖片描述

上面對msg函數進行了調用,fun_p是一個函數指針。

總結:

指針(Pointer)就是內存的地址,C語言允許用一個變量來存放指針,這種變量稱爲指針變量。指針變量可以存放基本類型數據的地址,也可以存放數組、函數以及其他指針變量的地址。

常見的指針含義:

- int *p;       p 可以指向 int 類型的數據,也可以指向類似 int arr[n] 的數組。
- int **p;      p 爲二級指針,指向 int * 類型的數據。
- int *p[n];    p 爲指針數組。[ ] 的優先級高於 *,所以應該理解爲 int *(p[n]);
- int (*p)[n];  p 爲二維數組指針。
- int *p();     p 是一個函數,它的返回值類型爲 int *。
- int (*p)();   p 是一個函數指針,指向原型爲 int func() 的函數。
發佈了91 篇原創文章 · 獲贊 55 · 訪問量 41萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章