C語言-指針

2020-08-12 14:18:23

以後,每遇到一個指針,都應該問問:這個指針的型別是什麼?指針指的型別是什麼?該指針指向了哪裏?

學習 C 語言的指針既簡單又有趣。通過指針,可以簡化一些 C 程式設計任務的執行,還有一些任務,如動態記憶體分配,沒有指針是無法執行的。所以,想要成爲一名優秀的 C 程式設計師,學習指針是很有必要的。

正如您所知道的,每一個變數都有一個記憶體位置,每一個記憶體位置都定義了可使用連字號(&)運算子存取的地址,它表示了在記憶體中的一個地址。請看下面 下麪的範例,它將輸出定義的變數地址:

#include <stdio.h>
int main ()
{
   int  var1;
   char var2[10];
   printf("var1 變數的地址: %p\n", &var1  );
   printf("var2 變數的地址: %p\n", &var2  );
   return 0;
}
var1 變數的地址: 0x7fff5cc109d4
var2 變數的地址: 0x7fff5cc109de

什麼是指針?

指針是一個變數,其值爲另一個變數的地址,即,記憶體位置的直接地址。就像其他變數或常數一樣,您必須在使用指針儲存其他變數地址之前,對其進行宣告。指針變數宣告的一般形式爲:
type *var-name;

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

int ip; / 一個整型的指針 */
double dp; / 一個 double 型的指針 */
float fp; / 一個浮點型的指針 */
char ch; / 一個字元型的指針 */

所有實際數據型別,不管是整型、浮點型、字元型,還是其他的數據型別,對應指針的值的型別都是一樣的,都是一個代表記憶體地址的長的十六進制數。

不同數據型別的指針之間唯一的不同是,指針所指向的變數或常數的數據型別不同。

如何使用指針?
使用指針時會頻繁進行以下幾個操作:定義一個指針變數、把變數地址賦值給指針、存取指針變數中可用地址的值。這些是通過使用一元運算子 * 來返回位於運算元所指定地址的變數的值。下面 下麪的範例涉及到了這些操作:

範例

#include <stdio.h>
 
int main ()
{
   int  var = 20;   /* 實際變數的宣告 */
   int  *ip;        /* 指針變數的宣告 */
 
   ip = &var;  /* 在指針變數中儲存 var 的地址 */
 
   printf("Address of var variable: %p\n", &var  );
 
   /* 在指針變數中儲存的地址 */
   printf("Address stored in ip variable: %p\n", ip );
 
   /* 使用指針存取值 */
   printf("Value of *ip variable: %d\n", *ip );
 
   return 0;
}

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

Address of var variable: bffd8b3c
Address stored in ip variable: bffd8b3c
Value of *ip variable: 20

NULL 指針

在變數宣告的時候,如果沒有確切的地址可以賦值,爲指針變數賦一個 NULL 值是一個良好的程式設計習慣。賦爲 NULL 值的指針被稱爲空指針。

NULL 指針是一個定義在標準庫中的值爲零的常數。請看下面 下麪的程式:

範例

#include <stdio.h>
 
int main ()
{
   int  *ptr = NULL;
 
   printf("ptr 的地址是 %p\n", ptr  );
 
   return 0;
}

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

ptr 的地址是 0x0
在大多數的操作系統上,程式不允許存取地址爲 0 的記憶體,因爲該記憶體是操作系統保留的。然而,記憶體地址 0 有特別重要的意義,它表明該指針不指向一個可存取的記憶體位置。但按照慣例,如果指針包含空值(零值),則假定它不指向任何東西。

如需檢查一個空指針,您可以使用 if 語句,如下所示:

if(ptr) /* 如果 p 非空,則完成 /
if(!ptr) /
如果 p 爲空,則完成 */

函數指針

函數指針是指向函數的指針變數。
通常我們說的指針變數是指向一個整型、字元型或陣列等變數,而函數指針是指向函數。
函數指針可以像一般函數一樣,用於呼叫函數、傳遞參數。

函數指針變數的宣告:

typedef int (*fun_ptr)(int,int); // 宣告一個指向同樣參數、返回值的函數指針型別
範例
以下範例宣告瞭函數指針變數 p,指向函數 max:

範例

#include <stdio.h>
 
int max(int x, int y)
{
    return x > y ? x : y;
}
 
int main(void)
{
    /* p 是函數指針 */
    int (* p)(int, int) = & max; // &可以省略
    int a, b, c, d;
 
    printf("請輸入三個數位:");
    scanf("%d %d %d", & a, & b, & c);
 
    /* 與直接呼叫函數等價,d = max(max(a, b), c) */
    d = p(p(a, b), c); 
 
    printf("最大的數位是: %d\n", d);
 
    return 0;

}
編譯執行,輸出結果如下:

請輸入三個數位:1 2 3
最大的數位是: 3