一. 回顧指針概念:
早在本系列第二篇中我就對(duì)指針的實(shí)質(zhì)進(jìn)行了闡述。今天我們又要學(xué)習(xí)一個(gè)叫做指向另一指針地址的指針。讓我們先回顧一下指針的概念吧!
當(dāng)我們程序如下申明變量:
short int i;
char a;
short int * pi;
程序會(huì)在內(nèi)存某地址空間上為各變量開(kāi)辟空間,如下圖所示。
內(nèi)存地址→6 7 8 9 10 11 12 13 14 15
-------------------------------------------------------------------------------------
… | | | | | | | | | |
-------------------------------------------------------------------------------------
|short int i |char a| |short int * pi|
圖中所示中可看出:
i 變量在內(nèi)存地址5的位置,占兩個(gè)字節(jié)。
a變量在內(nèi)存地址7的位置,占一個(gè)字節(jié)。
pi變量在內(nèi)存地址9的位置,占兩個(gè)字節(jié)。(注:pi 是指針,我這里指針的寬度只有兩個(gè)字節(jié),32位系統(tǒng)是四個(gè)字節(jié))
接下來(lái)如下賦值:
i=50;
pi=&i;
經(jīng)過(guò)上在兩句的賦值,變量的內(nèi)存映象如下:
內(nèi)存地址→6 7 8 9 10 11 12 13 14 15
--------------------------------------------------------------------------------------
… | 50 | | | 6 | | | |
--------------------------------------------------------------------------------------
|short int i |char a| |short int * pi|
看到?jīng)]有:短整型指針變量pi的值為6,它就是I變量的內(nèi)存起始地址。所以,這時(shí)當(dāng)我們對(duì)*pi進(jìn)行讀寫(xiě)操作時(shí),其實(shí)就是對(duì)i變量的讀寫(xiě)操作。如:
*pi=5; //就是等價(jià)于I=5;
二. 指針的地址與指向另一指針地址的指針
在上一節(jié)中,我們看到,指針變量本身與其它變量一樣也是在某個(gè)內(nèi)存地址中的,如pi的內(nèi)存起始地址是10。同樣的,我們也可能讓某個(gè)指針指向這個(gè)地址。
看下面代碼:
short int * * ppi; //這是一個(gè)指向指針的指針,注意有兩個(gè)*號(hào)
ppi=pi
第一句:short int * * ppi;——申明了一個(gè)指針變量ppi,這個(gè)ppi是用來(lái)存儲(chǔ)(或稱(chēng)指向)一個(gè)short int * 類(lèi)型指針變量的地址。
第二句:&pi那就是取pi的地址,ppi=pi就是把pi的地址賦給了ppi。即將地址值10賦值給ppi。如下圖:
內(nèi)存地址→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的內(nèi)容就是指針變量pi的起始地址。于是……
ppi的值是多少呢?——10。
*ppi的值是多少呢?——6,即pi的值。
**ppi的值是多少呢?——50,即I的值,也是*pi的值。
呵呵!不用我說(shuō)太多了,我相信你應(yīng)明白這種指針了吧!
三. 一個(gè)應(yīng)用實(shí)例
1. 設(shè)計(jì)一個(gè)函數(shù):void find1(char array[], char search, char * pi)
要求:這個(gè)函數(shù)參數(shù)中的數(shù)組array是以0值為結(jié)束的字符串,要求在字符串a(chǎn)rray中查找字符是參數(shù)search里的字符。如果找到,函數(shù)通過(guò)第三個(gè)參數(shù)(pa)返回值為array字符串中第一個(gè)找到的字符的地址。如果沒(méi)找到,則為pa為0。
設(shè)計(jì):依題意,實(shí)現(xiàn)代碼如下。
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;
}
}
}
你覺(jué)得這個(gè)函數(shù)能實(shí)現(xiàn)所要求的功能嗎?
調(diào)試:
我下面調(diào)用這個(gè)函數(shù)試試。
void main()
{
char str[]={“afsdfsdfdf\0”}; //待查找的字符串
char a=’d’; //設(shè)置要查找的字符
char * p=0; //如果查找到后指針p將指向字符串中查找到的第一個(gè)字符的地址。
find1(str,a,p); //調(diào)用函數(shù)以實(shí)現(xiàn)所要操作。
if (0==p )
{
printf (“沒(méi)找到!\n”);//1.如果沒(méi)找到則輸出此句
}
else
{
printf(“找到了,p=%d”,p); //如果找到則輸出此句
}
}
分析:
上面代碼,你認(rèn)為會(huì)是輸出什么呢?
運(yùn)行試試。
唉!怎么輸出的是:沒(méi)有找到!
而不是:找到了,……。
明明a值為’d’,而str字符串的第四個(gè)字符是’d’,應(yīng)該找得到呀!
再看函數(shù)定義處:void find1(char array[] , char search, char * pa)
看調(diào)用處:find1(str,a,p);
依我在第五篇的分析方法,函數(shù)調(diào)用時(shí)會(huì)對(duì)每一個(gè)參數(shù)進(jìn)行一個(gè)隱含的賦值操作。
整個(gè)調(diào)用如下:
array=str;
search=a;
pa=p; //請(qǐng)注意:以上三句是調(diào)用時(shí)隱含的動(dòng)作。
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;
}
}
哦!參數(shù)pa與參數(shù)search的傳遞并沒(méi)有什么不同,都是值傳遞嘛(小語(yǔ):地址傳遞其實(shí)就是地址值傳遞嘛)!所以對(duì)形參變量pa值(當(dāng)然值是一個(gè)地址值)的修改并不會(huì)改變實(shí)參變量p值,因此p的值并沒(méi)有改變(即p的指向并沒(méi)有被改變)。
(如果還有疑問(wèn),再看一看《函數(shù)參數(shù)的傳遞》了。)
修正:
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;
}
}
}
主函數(shù)的調(diào)用處改如下:
find2(str,a,&p); //調(diào)用函數(shù)以實(shí)現(xiàn)所要操作。
再分析:
這樣調(diào)用函數(shù)時(shí)的整個(gè)操作變成如下:
array=str;
search=a;
ppa=&p; //請(qǐng)注意:以上三句是調(diào)用時(shí)隱含的動(dòng)作。
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的地址。
對(duì)*ppa的修改就是對(duì)p值的修改。
下面看一下指向指針變量的指針變量怎樣正確引用。
用指向指針的指針變量訪(fǎng)問(wèn)一維和二維數(shù)組。
#include<stdio.h>
#include<stdlib.h>
main()
{
int a[3],b[2][2],*p1,*p2,**p3,i,j;
printf("請(qǐng)輸入一維數(shù)組的值:\n");
for(i=0;i<3;i++)
scanf("%d",&a[i]);/*一維數(shù)組的輸入*/
printf("請(qǐng)輸入二維數(shù)組的值:\n");
for(i=0;i<2;i++)
for(j=0;j<2;j++)
scanf("%d",&b[i][j]);/*二維數(shù)組輸入*/
printf("用指針輸出一維數(shù)組:\n");
for(p1=a,i=0;i<3;i++) /* 用指針輸出一維數(shù)組*/
{
printf("%4d",*(p1+i));
}
printf("\n");
printf("用指向指針的指針變量輸出一維數(shù)組(1):\n");
for(p1=a,p3=&p1,i=0;i<3;i++)
printf("%4d",*(*p3+i));/*用指向指針的指針變量輸出一維數(shù)組*/
printf("\n");
printf("用指向指針的指針變量輸出一維數(shù)組(2):\n");
for(p1=a;p1-a<3;p1++)/*用指向指針的指針變量輸出一維數(shù)組*/
{
p3=&p1;
printf("%4d",**p3);
}
printf("\n");
printf("用指針輸出二維數(shù)組:\n");
for(i=0;i<2;i++) /*用指針輸出二維數(shù)組*/
{
p2=b[i] ;
for(int j=0;j<2;j++)
{
printf("%4d",*(p2+j)) ;
}
}
printf("\n");
printf("用指向指針的指針變量輸出二維數(shù)組(1):\n");
for(i=0;i<2;i++)/*用指向指針的指針變量輸出二維數(shù)組*/
{
p2=b[i];
p3=&p2;
for(j=0;j<2;j++)
printf("%4d",*(*p3+j));
利用指向指針的指針變量對(duì)二維字符數(shù)組的訪(fǎng)問(wèn)。
#include<stdio.h>
#include<stdlib.h>
main()
{
int i;
char * ptr;
static char c[][16]={"clanguage","fox","computer","homepage"};
/*二維字符數(shù)組*/
static char *cp[]={c[0],c[1],c[2],c[3]};/*指針數(shù)組*/
static char **cpp;/*指向字符指針的指針變量*/
cpp=cp;/*將指針數(shù)組的首地址傳遞給指向字符指針的指針變量*/
for(i=0;i<4;i++)/*按行輸出字符串*/
printf("%s\n",*cpp++);
printf("-----------\n");
for(i=0;i<4;i++)/*按行輸出字符串*/
{
cpp=&cp[i];
printf("%s\n",*cpp);
}
printf("-----------\n");
for(i=0;i<4;i++)
{
ptr=c[i];
printf("%s",ptr);
printf("\n");
}
}
}
printf("\n");
printf("用指向指針的指針變量輸出二維數(shù)組(2):\n");
for(i=0;i<2;i++)/*用指向指針的指針變量輸出二維數(shù)組*/
{
p2=b[i];
for(p2=b[i];p2-b[i]<2;p2++)
{
p3=&p2;
printf("%4d",**p3);
}
printf("\n");
}
}