C語言中的指針

指針概念

指針是一個變量,該變量的數值是地址,或者說,指針是一個數據對象。

類似於,int 類型變量的數值是整數。

與指針相關的運算符

間接運算符:*

ptr 指向 bath,ptr = &bath

獲取 bath 中存放的數值,val = * ptr

上面兩句語句等價於 val = bath

地址運算符:&

後跟一個變量名時,& 給出該變量的地址。

指針聲明

int * pi;

int 表明被指向的變量的類型是整型,* 表示該變量是一個指針。pi 所指向的值(*pi)int 類型,pi
類型是“指向 int 的指針”。

* 和指針名之間的空格是可選的。

指針的輸出格式是 %p

使用指針在函數間通信

結合 PHP 中函數的引用賦值來理解。

變量的值在函數中改變還是全局改變。

指針和數組

概念

在 C 中,對一個指針加 1 的結果是對該指針增加 1 個存儲單元(storage unit)。對數組而言,地址會增加到下一個元素的地址,而
不是下一個字節。歸納如下:

  1. 指針的數值就是它所指向的對象的地址。對於包含多個字節的數據類型,對象的地址通常是指其首字節的地址。

  2. 在指針前運用運算符 * 可以得到該指針所指向的對象的數值。

  3. 對指針加1,等價於對指針的值加上它所指向的對象的字節大小。

函數、數組和指針

聲明數組參量

下面的四種原型都是等價的

int sum(int *ar, int n);
int sum(int *, int);
int sum(int ar[], int n);
int sum(int [], int);

定義函數時,下面兩種形式等價

int sum(int * ar, int n)
{
}

int sum(int ar[], int n)
{
}

聲明形式參量時,int *arint ar[] 都表示 ar 是指向 int 的指針。

sizeof 求變量、指針、數組大小。

使用指針參數

使用數組形參的函數需要知道數組的起點和終點。告知終點有兩種方法,一種是直接使用整數參量指明數組元素的個數,一種是用指針
指明數組的結束地址。比如,

int sum(int * start, int * end);

若數組的元素個數是 SIZE,那麼,* end 的值是 &start + SIZE(表示數組的最後一個元素後面的下一個元素)。

一元運算符 *++ 具有相等的優先級別,但它在結合時是從右向左進行的。

指針操作

指針基本操作

  1. 賦值(assignment)。

通常使用數組名或地址運算符&進行地址賦值。地址應該和指針類型兼容。

  1. 求職(value-finding)或取值(dereferencing)。

  2. 取指針地址。

  3. 將一個整數加給指針。

  4. 增加指針的值。

  5. 從指針中減去一個整數。

  6. 減小指針的值。

  7. 求差值(Differencing)。指向同一個數組內兩個元素的指針使用此運算。

  8. 比較。兩個指針具有相同的類型。

對未初始化的指針取值

不能對未初始化的指針取值。例如

int * pt;   // 未初始化的指針
*pt = 5;

合法的代碼

int i = 5;
int * pt = &i;

或者

double * ptd;
ptd = (double)malloc(30 * sizeof(double));

指針和多維數組

例程

#include <stdio.h>
int main(void)
{
    int zippo[4][2] = {{2, 4}, {6, 8}, {1, 3}, {5, 7}};

    printf("    zippo = %p,    zippo + 1 = %p\n",
           zippo,    zippo + 1);
    printf("zippo[0] = %p, zippo[0] + 1 = %p\n",
           zippo[0],    zippo[0] + 1);
    printf("  *zippo = %p,   *zippo + 1 = %p\n",
           *zippo, *zippo + 1);
    printf("zippo[0][0] = %d\n", zippo[0][0]);
    printf(" *zippo[0] = %d\n", *zippo[0]);
    printf("   **zippo = %d\n", **zippo);
    printf("    zippo[2][1] = %d\n", zippo[2][1]);
    printf("*(*(zippo+2) + 1) = %d\n", *(*(zippo+2) + 1));

    return 0;
}

代碼見 E:\code\c\c_primer_plus_c\10_15_zippo1.c

這段代碼中的疑點:*zippo[0]**zippo

聲明指向二維數組的指針變量

正確的代碼

int (* pz)[2];  // 聲明一個指向二維數組pz[n][2]的指針 

錯誤的代碼

int * pax[2];   // 創建一個兩個指針的數組

指針兼容

int n = 5;
double x;
int * pi = &n;
double * pd = &x;
x = n;  // 隱藏的類型轉換
pd = pi;    // 編譯時錯誤

假如有如下聲明:

int * pt;
int (*pa)[3];
int ar1[2][3];
int ar2[3][2];
int **p2;   // 指向指針的指針

那麼,有如下結論:

pt = &ar1[0][0];    // 都指向int
pt = ar1[0];        // 都指向int 
pt = ar1;   // 非法
pa = ar1;   // 都指向int[3]
pa = ar2;   // 非法
p2 = &pt;   // 都指向 int *
*p2 = ar2[0];   // 都指向int。不理解
p2 = ar2;   // 非法。不理解

保護數組內容

對形參使用 const

如果不打算在函數中修改數組,在函數原型和函數定義中對參數使用 const 可以達到目的。例程如下:

int sum(const int ar[], int n);

int sum(const int ar[], int n)
{
    int i;
    int total = 0;
    
    for(i = 0; i < n; i++)
        total += ar[i];
        
    return total;
}

使用了 const,在函數中試圖修改使用了 const 的參數時,編譯時會發現此錯誤。

有關 const 的其他內容

使用 const 創建符號常量。

const double PI = 3.14159;

指向常量的指針不能用於修改數值,但可以指向其他地址。

double rates[5] = {88.99, 100.12, 59.45, 183.11, 340.5};
const double * pd = rates;      // pd指向數組開始處

* pd = 29.89;   // 不允許
pd[2] = 222.22;     // 不允許 
rates[0] = 99.99;   // 允許,因爲 rates 不是常量
pd++;   // 讓pd指向rates[1],允許

將常量或非常量數據的地址賦給指向常量的指針是合法的。

double rates[5] = {88.99, 100.2, 59.45, 183.11, 340.5};
const double locked[4] = {0.08, 0.075, 0.0725, 0.07};
const double * pc = rates;  // 合法 
pc = locked;    // 合法 
pc = &rates[3]; // 合法 

只有非常量數據的地址纔可以賦給普通的指針。

double rates[5] = {88.99, 100.2, 59.45, 183.11, 340.5};
const double locked[4] = {0.08, 0.075, 0.0725, 0.07};

double * pnc = rates;   // 合法 
pnc = locked;   // 非法 
pnc = &rates[3];    // 合法 

使用 const 保證指針不會指向別處。

double rates[5] = {88.99, 100.2, 59.45, 183.11, 340.5};
double * const pc = rates;  // 指針指向數組的開始處
pc = &rates[2];     // 不允許 
*pc = 92.99;        // 可以 

使用 const 禁止修改所指向的數據。

double rates[5] = {88.99, 100.2, 59.45, 183.11, 340.5};
const double * const pc = rates;    // 指針指向數組的開始處
pc = &rates[2];     // 不允許 
*pc = 92.99;        // 不允許  

參考資料

《C Primer Plus(第五版)中文版》

  1. 指針簡介: P236-9.7
  2. 指針和數組: P254-10.3
  3. 函數、數組和指針: P256-10.4
  4. 指針操作: P260-10.5
  5. 指針和多維數組: P267-10.7
  6. 保護數組內容: P263-10.6
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章