c_lang_Reference_040820_03

文字來源 VC世界--C語言教室

自我存檔,也獻給和我一樣的DElphi程序員


數組指針變量的說明和使用

  指向數組的指針變量稱爲數組指針變量。
    一個數組是由連續的一塊內存單元組成的。
    數組名就是這塊連續內存單元的首地址。
    一個數組也是由各個數組元素(下標變量) 組成的。
    每個數組元素按其類型不同佔有幾個連續的內存單元。
    一個數組元素的首地址也是指它所佔有的幾個內存單元的首地址。
    一個指針變量既可以指向一個數組,也可以指向一個數組元素, 可把數組名或第一個元素的地址賦予它。
    如要使指針變量指向第i號元素可以把i元素的首地址賦予它或把數組名加i賦予它。

數組指針變量說明的一般形式爲:
類型說明符 * 指針變量名

引入指針變量後,就可以用兩種方法來訪問數組元素了。
  第一種方法爲下標法,即用a[i]形式訪問數組元素。 在第四章中介紹數組時都是採用這種方法。
  第二種方法爲指針法,即採用*(pa+i)形式,用間接訪問的方法來訪問數組元素。
main(){
int a[5],i,*pa;
pa=a;
for(i=0;i<5;i++){
*pa=i;
pa++;
}
pa=a;
for(i=0;i<5;i++){
printf("a[%d]=%d/n",i,*pa);
pa++;
}
}

下面,另舉一例,該例與上例本意相同,但是實現方式不同。
main(){
int a[5],i,*pa=a;
for(i=0;i<5;){
*pa=i;
printf("a[%d]=%d/n",i++,*pa++);
}
}

數組名和數組指針變量作函數參數

數組名就是數組的首地址,實參向形參傳送數組名實際上就是傳送數組的地址, 形參得到該地址後也指向同一數組。同樣,指針變量的值也是地址, 數組指針變量的值即爲數組的首地址,當然也可作爲函數的參數使用。
float aver(float *pa);
main(){
float sco[5],av,*sp;
int i;
sp=sco;
printf("/ninput 5 scores:/n");
for(i=0;i<5;i++) scanf("%f",&sco[i]);
av=aver(sp);
printf("average score is %5.2f",av);
}
float aver(float *pa)
{
int i;
float av,s=0;
for(i=0;i<5;i++) s=s+*pa++;
av=s/5;
return av;
}

指向多維數組的指針變量

本小節以二維數組爲例介紹多維數組的指針變量。

一、多維數組地址的表示方法
設有整型二維數組a[3][4]如下:
0 1 2 3
4 5 6 7
8 9 10 11
  設數組a的首地址爲1000,各下標變量的首地址及其值如圖所示。在第四章中介紹過, C語言允許把一個二維數組分解爲多個一維數組來處理。因此數組a可分解爲三個一維數組,即a[0],a[1],a[2]。每一個一維數組又含有四個元素。例如a[0]數組,含有a[0][0],a[0][1],a[0][2],a[0][3]四個元素。 數組及數組元素的地址表示如下:a是二維數組名,也是二維數組0行的首地址,等於1000。a[0]是第一個一維數組的數組名和首地址,因此也爲1000。*(a+0)或*a是與a[0]等效的, 它表示一維數組a[0]0 號元素的首地址。 也爲1000。&a[0][0]是二維數組a的0行0列元素首地址,同樣是1000。因此,a,a[0],*(a+0),*a,&a[0][0]是相等的。同理,a+1是二維數組1行的首地址,等於1008。a[1]是第二個一維數組的數組名和首地址,因此也爲1008。 &a[1][0]是二維數組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]也是等同的。因爲在二維數組中不能把&a[i]理解爲元素a[i]的地址,不存在元素a[i]。

  C語言規定,它是一種地址計算方法,表示數組a第i行首地址。由此,我們得出:a[i],&a[i],*(a+i)和a+i也都是等同的。另外,a[0]也
可以看成是a[0]+0是一維數組a[0]的0號元素的首地址, 而a[0]+1則是a[0]的1號元素首地址,由此可得出a[i]+j則是一維數組a[i]的j號元素首地址,它等於&a[i][j]。由a[i]=*(a+i)得a[i]+j=*(a+i)+j,由於*(a+i)+j是二維數組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));
}

二、多維數組的指針變量

  把二維數組a 分解爲一維數組a[0],a[1],a[2]之後,設p爲指向二維數組的指針變量。可定義爲: int (*p)[4] 它表示p是一個指針變量,它指向二維數組a 或指向第一個一維數組a[0],其值等於a,a[0],或&a[0][0]等。而p+i則指向一維數組a[i]。從前面的分析可得出*(p+i)+j是二維數組i行j 列的元素的地址,而*(*(p+i)+j)則是i行j列元素的值。

  二維數組指針變量說明的一般形式爲: 類型說明符 (*指針變量名)[長度] 其中“類型說明符”爲所指數組的數據類型。“*”表示其後的變量是指針類型。 “長度”表示二維數組分解爲多個一維數組時, 一維數組的長度,也就是二維數組的列數。應注意“(*指針變量名)”兩邊的括號不可少,如缺少括號則表示是指針數組(本章後面介紹),意義就完全不同了。
[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字符串指針變量的說明和使用字符串指針變量的定義說明與指向字符變量的指針變量說明是相同的。只能按對指針變量的賦值不同來區別。 對指向字符變量的指針變量應賦予該字符變量的地址。如: char c,*p=&c;表示p是一個指向字符變量c的指針變量。而: char *s="C Language";則表示s是一個指向字符串的指針變量。把字符串的首地址賦予s。
請看下面一例。
main(){
char *ps;
ps="C Language";
printf("%s",ps);
}
運行結果爲:
C Language
上例中,首先定義ps是一個字符指針變量, 然後把字符串的首地址賦予ps(應寫出整個字符串,以便編譯系統把該串裝入連續的一塊內存單元),並把首地址送入ps。程序中的: char *ps;ps="C Language";等效於: char *ps="C Language";輸出字符串中n個字符後的所有字符。
main(){
char *ps="this is a book";
int n=10;
ps=ps+n;
printf("%s/n",ps);
}
運行結果爲:
book 在程序中對ps初始化時,即把字符串首地址賦予ps,當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’字符。 下面這個例子是將指針變量指向一個格式字符串,用在printf函數中,用於輸出二維數組的各種地址表示的值。但在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));
}
  在下例是講解,把字符串指針作爲函數參數的使用。要求把一個字符串的內容複製到另一個字符串中,並且不能使用strcpy函數。函數cprstr的形參爲兩個字符指針變量。pss指向源字符串,pds指向目標字符串。表達式:
(*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);
}
  在上例中,程序完成了兩項工作:一是把pss指向的源字符複製到pds所指向的目標字符中,二是判斷所複製的字符是否爲`/0',若是則表明源字符串結束,不再循環。否則,pds和pss都加1,指向下一字符。在主函數中,以指針變量pa,pb爲實參,分別取得確定值後調用cprstr函數。由於採用的指針變量pa和pss,pb和pds均指向同一字符串,因此在主函數和cprstr函數中均可使用這些字符串。也可以把cprstr函數簡化爲以下形式:
cprstr(char *pss,char*pds)
{while ((*pds++=*pss++)!=`/0');}
  即把指針的移動和賦值合併在一個語句中。 進一步分析還可發現`/0'的ASCⅡ碼爲0,對於while語句只看表達式的值爲非0就循環,爲0則結束循環,因此也可省去“!=`/0'”這一判斷部分,而寫爲以下形式:
cprstr (char *pss,char *pds)
{while (*pdss++=*pss++);}
表達式的意義可解釋爲,源字符向目標字符賦值, 移動指針,若所賦值爲非0則循環,否則結束循環。這樣使程序更加簡潔。簡化後的程序如下所示。
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);
}

使用字符串指針變量與字符數組的區別

用字符數組和字符指針變量都可實現字符串的存儲和運算。 但是兩者是有區別的。在使用時應注意以下幾個問題:

1. 字符串指針變量本身是一個變量,用於存放字符串的首地址。而字符串本身是存放在以該首地址爲首的一塊連續的內存空間中並以‘/0’作爲串的結束。字符數組是由於若干個數組元素組成的,它可用來存放整個字符串。

2. 對字符數組作初始化賦值,必須採用外部類型或靜態類型,如: static char st[]={“C Language”};而對字符串指針變量則無此限制,如: char *ps="C Language";

3. 對字符串指針方式 char *ps="C Language";可以寫爲: char *ps; ps="C Language";而對數組方式:
static char st[]={"C Language"};
不能寫爲:
char st[20];st={"C Language"};
而只能對字符數組的各元素逐個賦值。

  從以上幾點可以看出字符串指針變量與字符數組在使用時的區別,同時也可看出使用指針變量更加方便。前面說過,當一個指針變量在未取得確定地址前使用是危險的,容易引起錯誤。但是對指針變量直接賦值是可以的。因爲C系統對指針變量賦值時要給以確定的地址。因此,
char *ps="C Langage";
或者 char *ps;
ps="C Language";都是合法的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章