1. 程式人生 > >徹底搞定C指標---指向指標的指標

徹底搞定C指標---指向指標的指標

http://www.eefocus.com/max_lpy/blog/10-09/195288_05ca9.html

一. 回顧指標概念:

今天我們又要學習一個叫做指向另一指標地址的指標。讓我們先回顧一下指標的概念吧!
當我們程式如下申明變數:
short int i;
char a;
short int * pi;
程式會在記憶體某地址空間上為各變數開闢空間,如下圖所示。
記憶體地址→6     7      8     9     10     11    12    13     14    15
-------------------------------------------------------------------------------------

…  |     |      |      |      |      |       |      |      |      |    
-------------------------------------------------------------------------------------
     |short int i |char a|      |short int * pi|
圖中所示中可看出:
i 變數在記憶體地址5的位置,佔兩個位元組。
a變數在記憶體地址7的位置,佔一個位元組。
pi變數在記憶體地址9的位置,佔兩個位元組。(注:pi 是指標,我這裡指標的寬度只有兩個位元組,32位系統是四個位元組)

接下來如下賦值:
i=50;
pi=&i;
經過上在兩句的賦值,變數的記憶體映象如下:
記憶體地址→6     7      8     9     10     11    12    13      14     15
--------------------------------------------------------------------------------------
…  |    50      |      |      |    6         |      |      |       |    
--------------------------------------------------------------------------------------

     |short int i |char a|      |short int * pi|
看到沒有:短整型指標變數pi的值為6,它就是I變數的記憶體起始地址。所以,這時當我們對*pi進行讀寫操作時,其實就是對i變數的讀寫操作。如:
*pi=5;   //就是等價於I=5;
你可以回看本系列的第二篇,那裡有更加詳細的解說。

二. 指標的地址與指向另一指標地址的指標
在上一節中,我們看到,指標變數本身與其它變數一樣也是在某個記憶體地址中的,如pi的記憶體起始地址是10。同樣的,我們也可能讓某個指標指向這個地址。
看下面程式碼:
short int * * ppi;    //這是一個指向指標的指標,注意有兩個*號
ppi=π

第一句:short int * * ppi;——申明瞭一個指標變數ppi,這個ppi是用來儲存(或稱指向)一個short int * 型別指標變數的地址。
第二句:&pi那就是取pi的地址,ppi=π就是把pi的地址賦給了ppi。即將地址值10賦值給ppi。如下圖:
記憶體地址→6     7      8     9     10     11    12    13       14    15
------------------------------------------------------------------------------------
…  |    50     |      |      |      6       |       10      |      |    
------------------------------------------------------------------------------------
     |short int i|char a|      |short int * pi|short int ** ppi|
從圖中看出,指標變數ppi的內容就是指標變數pi的起始地址。於是……
ppi的值是多少呢?——10。
*ppi的值是多少呢?——6,即pi的值。
**ppi的值是多少呢?——50,即I的值,也是*pi的值。
呵呵!不用我說太多了,我相信你應明白這種指標了吧!

三. 一個應用例項
1. 設計一個函式:void find1(char array[], char search, char * pi)
要求:這個函式引數中的陣列array是以0值為結束的字串,要求在字串array中查詢字元是引數search裡的字元。如果找到,函式通過第三個引數(pa)返回值為array字串中第一個找到的字元的地址。如果沒找到,則為pa為0。
設計:依題意,實現程式碼如下。
void find1(char [] array, char search, char * pa)
{
    int i;
    for (i=0;*(array+i)!=0;i++)
    {
       if (*(array+i)==search)
       {
         pa=array+i
         break;
       }
       else if (*(array+i)==0)
       {
         pa=0;
         break;
       }
    }
}
你覺得這個函式能實現所要求的功能嗎?
除錯:
我下面呼叫這個函式試試。
void main()
{
   char str[]={“afsdfsdfdf\0”};  //待查詢的字串
   char a=’d’;   //設定要查詢的字元
   char * p=0;  //如果查詢到後指標p將指向字串中查詢到的第一個字元的地址。
   find1(str,a,p);  //呼叫函式以實現所要操作。
   if (0==p )
   {
      printf (“沒找到!\n”);//1.如果沒找到則輸出此句
   }
   else
   {
      printf(“找到了,p=%d”,p);  //如果找到則輸出此句
   }
}
分析:
上面程式碼,你認為會是輸出什麼呢?
執行試試。
唉!怎麼輸出的是:沒有找到!
而不是:找到了,……。
明明a值為’d’,而str字串的第四個字元是’d’,應該找得到呀!
再看函式定義處:void find1(char [] array, char search, char * pa)
看呼叫處:find1(str,a,p);
依我在第五篇的分析方法,函式呼叫時會對每一個引數進行一個隱含的賦值操作。
整個呼叫如下:
    array=str;
    search=a;
    pa=p;    //請注意:以上三句是呼叫時隱含的動作。
    int i;
    for (i=0;*(array+i)!=0;i++)
    {
       if (*(array+i)==search)
       {
         pa=array+i
         break;
       }
       else if (*(array+i)==0)
       {
         pa=0;
         break;
       }
    }
哦!引數pa與引數search的傳遞並沒有什麼不同,都是值傳遞嘛(小語:地址傳遞其實就是地址值傳遞嘛)!所以對形參變數pa值(當然值是一個地址值)的修改並不會改變實參變數p值,因此p的值並沒有改變(即p的指向並沒有被改變)。
(如果還有疑問,再看一看《第五篇:函式引數的傳遞》了。)
修正:
void find2(char [] array, char search, char ** ppa)
{
    int i;
    for (i=0;*(array+i)!=0;i++)
    {
       if (*(array+i)==search)
       {
         *ppa=array+i
         break;
       }
       else if (*(array+i)==0)
       {
         *ppa=0;
         break;
       }
    }
}
主函式的呼叫處改如下:
   find2(str,a,&p);  //呼叫函式以實現所要操作。
再分析:
這樣呼叫函式時的整個操作變成如下:
    array=str;
    search=a;
    ppa=&p;    //請注意:以上三句是呼叫時隱含的動作。
    int i;
    for (i=0;*(array+i)!=0;i++)
    {
       if (*(array+i)==search)
       {
         *ppa=array+i
         break;
       }
       else if (*(array+i)==0)
       {
         *ppa=0;
         break;
       }
    }
看明白了嗎?
ppa指向指標p的地址。
對*ppa的修改就是對p值的修改。
你自行去除錯。
經過修改後的程式就可以完成所要的功能了。