一、多維數(shù)組地址的表示方法
設(shè)有整型二維數(shù)組a[3][4]如下:
0 1 2 3
4 5 6 7
8 9 10 11
設(shè)數(shù)組a的首地址為1000,各下標(biāo)變量的首地址及其值如圖所示。
在前面曾經(jīng)介紹過, C語言允許把一個(gè)二維數(shù)組分解為多個(gè)一維數(shù)組來處理。因此數(shù)組a可分解為三個(gè)一維數(shù)組,即a[0],a[1],a[2]。每一個(gè)一維數(shù)組又含有四個(gè)元素。例如a[0]數(shù)組,含有a[0][0],a[0][1],a[0][2],a[0][3]四個(gè)元素。 數(shù)組及數(shù)組元素的地址表示如下:a是二維數(shù)組名,也是二維數(shù)組0行的首地址,等于1000。a[0]是第一個(gè)一維數(shù)組的數(shù)組名和首地址,因此也為1000。*(a+0)或*a是與a[0]等效的, 它表示一維數(shù)組a[0]0 號(hào)元素的首地址。 也為1000。&a[0][0]是二維數(shù)組a的0行0列元素首地址,同樣是1000。因此,a,a[0],*(a+0),*a,&a[0][0]是相等的。同理,a+1是二維數(shù)組1行的首地址,等于1008。a[1]是第二個(gè)一維數(shù)組的數(shù)組名和首地址,因此也為1008。 &a[1][0]是二維數(shù)組a的1行0列元素地址,也是1008。因此a+1,a[1],*(a+1),&a[1][0]是等同的。 由此可得出:a+i,a[i],*(a+i),&a[i][0]是等同的。 此外,&a[i]和a[i]也是等同的。因?yàn)樵诙S數(shù)組中不能把&a[i]理解為元素a[i]的地址,不存在元素a[i]。
C語言規(guī)定,它是一種地址計(jì)算方法,表示數(shù)組a第i行首地址。由此,我們得出:a[i],&a[i],*(a+i)和a+i也都是等同的。另外,a[0]也可以看成是a[0]+0是一維數(shù)組a[0]的0號(hào)元素的首地址, 而a[0]+1則是a[0]的1號(hào)元素首地址,由此可得出a[i]+j則是一維數(shù)組a[i]的j號(hào)元素首地址,它等于&a[i][j]。由a[i]=*(a+i)得a[i]+j=*(a+i)+j,由于*(a+i)+j是二維數(shù)組a的i行j列元素的首地址。該元素的值等于*(*(a+i)+j)。
[Explain]
#define PF "%d,%d,%d,%d,%d,\n"
main(){
static int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
printf(PF,a,*a,a[0],&a[0],&a[0][0]);
printf(PF,a+1,*(a+1),a[1],&a[1],&a[1][0]);
printf(PF,a+2,*(a+2),a[2],&a[2],&a[2][0]);
printf("%d,%d\n",a[1]+1,*(a+1)+1);
printf("%d,%d\n",*(a[1]+1),*(*(a+1)+1));
}
二、多維數(shù)組的指針變量
把二維數(shù)組a 分解為一維數(shù)組a[0],a[1],a[2]之后,設(shè)p為指向二維數(shù)組的指針變量??啥x為: int (*p)[4] 它表示p是一個(gè)指針變量,它指向二維數(shù)組a 或指向第一個(gè)一維數(shù)組a[0],其值等于a,a[0],或&a[0][0]等。而p+i則指向一維數(shù)組a[i]。從前面的分析可得出*(p+i)+j是二維數(shù)組i行j 列的元素的地址,而*(*(p+i)+j)則是i行j列元素的值。
二維數(shù)組指針變量說明的一般形式為: 類型說明符 (*指針變量名)[長(zhǎng)度] 其中“類型說明符”為所指數(shù)組的數(shù)據(jù)類型。“*”表示其后的變量是指針類型。 “長(zhǎng)度”表示二維數(shù)組分解為多個(gè)一維數(shù)組時(shí), 一維數(shù)組的長(zhǎng)度,也就是二維數(shù)組的列數(shù)。應(yīng)注意“(*指針變量名)”兩邊的括號(hào)不可少,如缺少括號(hào)則表示是指針數(shù)組(本章后面介紹),意義就完全不同了。
[Explain]
main(){
static int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
int(*p)[4];
int i,j;
p=a;
for(i=0;i<3;i++)
for(j=0;j<4;j++) printf("%2d ",*(*(p+i)+j));
}
‘Expain字符串指針變量的說明和使用字符串指針變量的定義說明與指向字符變量的指針變量說明是相同的。只能按對(duì)指針變量的賦值不同來區(qū)別。 對(duì)指向字符變量的指針變量應(yīng)賦予該字符變量的地址。如: char c,*p=&c;表示p是一個(gè)指向字符變量c的指針變量。而: char *s="C Language";則表示s是一個(gè)指向字符串的指針變量。把字符串的首地址賦予s。
請(qǐng)看下面一例。
main(){
char *ps;
ps="C Language";
printf("%s",ps);
}
運(yùn)行結(jié)果為:
C Language
上例中,首先定義ps是一個(gè)字符指針變量, 然后把字符串的首地址賦予ps(應(yīng)寫出整個(gè)字符串,以便編譯系統(tǒng)把該串裝入連續(xù)的一塊內(nèi)存單元),并把首地址送入ps。程序中的: char *ps;ps="C Language";等效于: char *ps="C Language";輸出字符串中n個(gè)字符后的所有字符。
main(){
char *ps="this is a book";
int n=10;
ps=ps+n;
printf("%s\n",ps);
}
運(yùn)行結(jié)果為:
book 在程序中對(duì)ps初始化時(shí),即把字符串首地址賦予ps,當(dāng)ps= ps+10之后,ps指向字符“b”,因此輸出為"book"。
main(){
char st[20],*ps;
int i;
printf("input a string:\n");
ps=st;
scanf("%s",ps);
for(i=0;ps[i]!=‘\0‘;i++)
if(ps[i]==‘k‘){
printf("there is a ‘k‘ in the string\n");
break;
}
if(ps[i]==‘\0‘) printf("There is no ‘k‘ in the string\n");
}
本例是在輸入的字符串中查找有無‘k’字符。 下面這個(gè)例子是將指針變量指向一個(gè)格式字符串,用在printf函數(shù)中,用于輸出二維數(shù)組的各種地址表示的值。但在printf語句中用指針變量PF代替了格式串。 這也是程序中常用的方法。
main(){
static int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
char *PF;
PF="%d,%d,%d,%d,%d\n";
printf(PF,a,*a,a[0],&a[0],&a[0][0]);
printf(PF,a+1,*(a+1),a[1],&a[1],&a[1][0]);
printf(PF,a+2,*(a+2),a[2],&a[2],&a[2][0]);
printf("%d,%d\n",a[1]+1,*(a+1)+1);
printf("%d,%d\n",*(a[1]+1),*(*(a+1)+1));
}
在下例是講解,把字符串指針作為函數(shù)參數(shù)的使用。要求把一個(gè)字符串的內(nèi)容復(fù)制到另一個(gè)字符串中,并且不能使用strcpy函數(shù)。函數(shù)cprstr的形參為兩個(gè)字符指針變量。pss指向源字符串,pds指向目標(biāo)字符串。表達(dá)式:
(*pds=*pss)!=`\0‘
cpystr(char *pss,char *pds){
while((*pds=*pss)!=‘\0‘){
pds++;
pss++; }
}
main(){
char *pa="CHINA",b[10],*pb;
pb=b;
cpystr(pa,pb);
printf("string a=%s\nstring b=%s\n",pa,pb);
}
在上例中,程序完成了兩項(xiàng)工作:一是把pss指向的源字符復(fù)制到pds所指向的目標(biāo)字符中,二是判斷所復(fù)制的字符是否為`\0‘,若是則表明源字符串結(jié)束,不再循環(huán)。否則,pds和pss都加1,指向下一字符。在主函數(shù)中,以指針變量pa,pb為實(shí)參,分別取得確定值后調(diào)用cprstr函數(shù)。由于采用的指針變量pa和pss,pb和pds均指向同一字符串,因此在主函數(shù)和cprstr函數(shù)中均可使用這些字符串。也可以把cprstr函數(shù)簡(jiǎn)化為以下形式:
cprstr(char *pss,char*pds)
{while ((*pds++=*pss++)!=`\0‘);}
即把指針的移動(dòng)和賦值合并在一個(gè)語句中。 進(jìn)一步分析還可發(fā)現(xiàn)`\0‘的ASCⅡ碼為0,對(duì)于while語句只看表達(dá)式的值為非0就循環(huán),為0則結(jié)束循環(huán),因此也可省去“!=`\0‘”這一判斷部分,而寫為以下形式:
cprstr (char *pss,char *pds)
{while (*pdss++=*pss++);}
表達(dá)式的意義可解釋為,源字符向目標(biāo)字符賦值, 移動(dòng)指針,若所賦值為非0則循環(huán),否則結(jié)束循環(huán)。這樣使程序更加簡(jiǎn)潔。簡(jiǎn)化后的程序如下所示。
cpystr(char *pss,char *pds){
while(*pds++=*pss++);
}
main(){
char *pa="CHINA",b[10],*pb;
pb=b;
cpystr(pa,pb);
printf("string a=%s\nstring b=%s\n",pa,pb);
}
使用字符串指針變量與字符數(shù)組的區(qū)別
用字符數(shù)組和字符指針變量都可實(shí)現(xiàn)字符串的存儲(chǔ)和運(yùn)算。 但是兩者是有區(qū)別的。在使用時(shí)應(yīng)注意以下幾個(gè)問題:
1. 字符串指針變量本身是一個(gè)變量,用于存放字符串的首地址。而字符串本身是存放在以該首地址為首的一塊連續(xù)的內(nèi)存空間中并以‘\0’作為串的結(jié)束。字符數(shù)組是由于若干個(gè)數(shù)組元素組成的,它可用來存放整個(gè)字符串。
2. 對(duì)字符數(shù)組作初始化賦值,必須采用外部類型或靜態(tài)類型,如: static char st[]={“C Language”};而對(duì)字符串指針變量則無此限制,如: char *ps="C Language";
3. 對(duì)字符串指針方式 char *ps="C Language";可以寫為: char *ps; ps="C Language";而對(duì)數(shù)組方式:
static char st[]={"C Language"};
不能寫為:
char st[20];st={"C Language"};
而只能對(duì)字符數(shù)組的各元素逐個(gè)賦值。
從以上幾點(diǎn)可以看出字符串指針變量與字符數(shù)組在使用時(shí)的區(qū)別,同時(shí)也可看出使用指針變量更加方便。前面說過,當(dāng)一個(gè)指針變量在未取得確定地址前使用是危險(xiǎn)的,容易引起錯(cuò)誤。但是對(duì)指針變量直接賦值是可以的。因?yàn)镃系統(tǒng)對(duì)指針變量賦值時(shí)要給以確定的地址。因此,
char *ps="C Langage";
或者
char *ps;
ps="C Language";
都是合法的。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)
點(diǎn)擊舉報(bào)。