1. 程式人生 > >深入理解C語言中兩級指標(char **pptr)的引數的用法

深入理解C語言中兩級指標(char **pptr)的引數的用法

最近在看亞嵌的《Linux C程式設計一站式學習》,對其中的兩層指標的引數用法有些疑惑,下面和大家分享一下學習心得!

首先來看一段程式碼:

/* main.c */
#include <stdio.h>
#include <stdlib.h>

static const char *msgg[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

void get_w_day(const char **pp)
{
     pp[0] = msgg[2]; // *pp     = msgg[0];
     pp[1] = msgg[3]; // *(pp+1) = msgg[1];
}

int main(void)
{
          char  ptr[2] = {};
    const char  *pptr = ptr;    //這裡初始化也可以為NULL,不會導致編譯出錯和執行時的段錯誤,但在實際程式中最好詳細初始化
    const char **ppptr = &pptr; //在ppptr引數傳入get_w_day()函式之前,必須對其進行初始化,否則會導致執行時的段錯誤
 				//仔細想一下原因,如果ppptr是NULL,那麼get_w_day()函式修改的*ppptr就會修改一個不確定的位置
                                //進一步從底層查詢原因,如果ppptr是NULL,那麼傳入get_w_day()時刻的實際值就是0x0,也就是我們要操作*((char*)0x00) = ??
                                //這樣必然導致一個段錯誤
    get_w_day(ppptr);
    
    char fuck      = **ppptr + 1;     //這裡的fuck應該等於幾? 答案是'U' ==> 'T'+1  
    char fuckk     = *(*ppptr + 1);   //如果是 fuck = *(*ppptr + 1) 呢? 答案是 'u' ==> 指向"Tuesday"頭指標加1
    char fuckkk    = **(ppptr + 1);   //如果是  **(ppptr + 1)呢?答案是'V'
    char fuckkkk   = **((ppptr+1) + 1 //是'W' ==> 'V'+1
    char fuckkkkk  = **((ppptr+2) + 1 //是一個不確定的值,有可能引起段錯誤
    printf("%s\t%s\n", *ppptr, *(ppptr+1));  
    return 0;
}


指標就是指向記憶體地址的變數,二級指標也是指標,即指向指標的指標,同樣可以表示傳入引數、傳出引數或者Value-result引數,只不過該引數所指的記憶體空間應該解釋成一個指標變數。

這裡有一個法則,傳入一個N級的指標,就可以修改N-1級的指標,原因是C語言的引數傳遞是按值傳遞的,直接修改形參是無法改變實參的,但可以通過傳入的指標引數修改其指向的的內容,N級指標指向的內容就是一個N-1級的指標,邊界情況就是引數是一個非指標型別的變數,可以理解為0級指標,這樣就修改不了其內容。

對於上述程式碼,可以在gei_w_day()函式中,修改一級指標的內容,即可以修改×ppptr的值,而*ppptr 對應 pptr,這裡把他看成一個字串陣列名,從而可以理解為可以在gei_w_day()

函式中改變字串陣列中的0項、1項...的值。

        在來看看形參中const的作用,如下程式碼所示,

char ** p1;        // int元素不可修改
char * const * p2; // int *一級指標不可修改
char ** const p3;  // int **二級指標不可修改

思考題:
//思考題:如果將下述程式碼做改動,那麼 printf("%s\t%s\n", *ppptr, *(ppptr+2)); 能否打印出
void get_w_day(const char **pp)
{
     pp[0] = msgg[2]; 
     pp[1] = msgg[3];
     pp[2] = msgg[4]; //新增...
}