第六章:C語(yǔ)言指針(下)
1. 多維數(shù)組的指針變量
把二維數(shù)組a 分解為一維數(shù)組a[0],a[1],a[2]之后,設(shè)p為指向二維數(shù)組的指針變量。可定義為: 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ù)組指針變量說(shuō)明的一般形式為: 類型說(shuō)明符 (指針變量名)[長(zhǎng)度] 其中“類型說(shuō)明符”為所指數(shù)組的數(shù)據(jù)類型。“”表示其后的變量是指針類型。 “長(zhǎng)度”表示二維數(shù)組分解為多個(gè)一維數(shù)組時(shí), 一維數(shù)組的長(zhǎng)度,也就是二維數(shù)組的列數(shù)。應(yīng)注意“(*指針變量名)”兩邊的括號(hào)不可少,如缺少括號(hào)則表示是指針數(shù)組(本章后面介紹),意義就完全不同了。
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字符串指針變量的說(shuō)明和使用字符串指針變量的定義說(shuō)明與指向字符變量的指針變量說(shuō)明是相同的。只能按對(duì)指針變量的賦值不同來(lái)區(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]!='
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"); }
';i++) if(ps[i]=='k'){ printf("there is a 'k' in the string\n"); break; } if(ps[i]=='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"); }
') printf("There is no 'k' in the string\n"); }本例是在輸入的字符串中查找有無(wú)‘k’字符。 下面這個(gè)例子是將指針變量指向一個(gè)格式字符串,用在printf函數(shù)中,用于輸出二維數(shù)組的各種地址表示的值。但在printf語(yǔ)句中用指針變量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)!=`
(*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); }
' cpystr(char *pss,char *pds){ while((*pds=*pss)!='(*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); }
'){ 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ù)制的字符是否為`
在上例中,程序完成了兩項(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ù)中均可使用這些字符串。
’,若是則表明源字符串結(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++)!=`
cprstr(char *pss,char*pds) {while ((*pds++=*pss++)!=`\0');}
');}即把指針的移動(dòng)和賦值合并在一個(gè)語(yǔ)句中。 進(jìn)一步分析還可發(fā)現(xiàn)
即把指針的移動(dòng)和賦值合并在一個(gè)語(yǔ)句中。 進(jìn)一步分析還可發(fā)現(xiàn)\0'的ASCⅡ碼為0,對(duì)于while語(yǔ)句只看表達(dá)式的值為非0就循環(huán),為0則結(jié)束循環(huán),因此也可省去“!=\0’”這一判斷部分,而寫為以下形式:
'的ASCⅡ碼為0,對(duì)于while語(yǔ)句只看表達(dá)式的值為非0就循環(huán),為0則結(jié)束循環(huán),因此也可省去“!=即把指針的移動(dòng)和賦值合并在一個(gè)語(yǔ)句中。 進(jìn)一步分析還可發(fā)現(xiàn)\0'的ASCⅡ碼為0,對(duì)于while語(yǔ)句只看表達(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); }
2. 使用字符串指針變量與字符數(shù)組的區(qū)別
用字符數(shù)組和字符指針變量都可實(shí)現(xiàn)字符串的存儲(chǔ)和運(yùn)算。 但是兩者是有區(qū)別的。在使用時(shí)應(yīng)注意以下幾個(gè)問(wèn)題:
字符串指針變量本身是一個(gè)變量,用于存放字符串的首地址。而字符串本身是存放在以該首地址為首的一塊連續(xù)的內(nèi)存空間中并以‘
字符串指針變量本身是一個(gè)變量,用于存放字符串的首地址。而字符串本身是存放在以該首地址為首的一塊連續(xù)的內(nèi)存空間中并以‘\0’作為串的結(jié)束。字符數(shù)組是由于若干個(gè)數(shù)組元素組成的,它可用來(lái)存放整個(gè)字符串。
’作為串的結(jié)束。字符數(shù)組是由于若干個(gè)數(shù)組元素組成的,它可用來(lái)存放整個(gè)字符串。對(duì)字符數(shù)組作初始化賦值,必須采用外部類型或靜態(tài)類型,如: static char st[]={“C Language”};而對(duì)字符串指針變量則無(wú)此限制,如: char *ps=“C Language”;
對(duì)字符串指針?lè)绞?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í)也可看出使用指針變量更加方便。前面說(shuō)過(guò),當(dāng)一個(gè)指針變量在未取得確定地址前使用是危險(xiǎn)的,容易引起錯(cuò)誤。但是對(duì)指針變量直接賦值是可以的。因?yàn)镃系統(tǒng)對(duì)指針變量賦值時(shí)要給以確定的地址。
因此,
char *ps="C Langage"; 或者 char *ps; ps="C Language";都是合法的。
3. 函數(shù)指針變量
在C語(yǔ)言中規(guī)定,一個(gè)函數(shù)總是占用一段連續(xù)的內(nèi)存區(qū), 而函數(shù)名就是該函數(shù)所占內(nèi)存區(qū)的首地址。 我們可以把函數(shù)的這個(gè)首地址(或稱入口地址)賦予一個(gè)指針變量, 使該指針變量指向該函數(shù)。然后通過(guò)指針變量就可以找到并調(diào)用這個(gè)函數(shù)。 我們把這種指向函數(shù)的指針變量稱為“函數(shù)指針變量”。
函數(shù)指針變量定義的一般形式為:
類型說(shuō)明符 (*指針變量名)();
其中“類型說(shuō)明符”表示被指函數(shù)的返回值的類型。“(* 指針變量名)”表示“*”后面的變量是定義的指針變量。 最后的空括號(hào)表示指針變量所指的是一個(gè)函數(shù)。
例如: int (*pf)();
表示pf是一個(gè)指向函數(shù)入口的指針變量,該函數(shù)的返回值(函數(shù)值)是整型。
下面通過(guò)例子來(lái)說(shuō)明用指針形式實(shí)現(xiàn)對(duì)函數(shù)調(diào)用的方法。
int max(int a,int b){ if(a>b)return a; else return b; } main(){ int max(int a,int b); int(*pmax)(); int x,y,z; pmax=max; printf("input two numbers:\n"); scanf("%d%d",&x,&y); z=(*pmax)(x,y); printf("maxmum=%d",z); }
從上述程序可以看出用,函數(shù)指針變量形式調(diào)用函數(shù)的步驟如下:1. 先定義函數(shù)指針變量,如后一程序中第9行 int (*pmax)();定義pmax為函數(shù)指針變量。
把被調(diào)函數(shù)的入口地址(函數(shù)名)賦予該函數(shù)指針變量,如程序中第11行 pmax=max;
用函數(shù)指針變量形式調(diào)用函數(shù),如程序第14行 z=(*pmax)(x,y); 調(diào)用函數(shù)的一般形式為: (*指針變量名) (實(shí)參表)使用函數(shù)指針變量還應(yīng)注意以下兩點(diǎn):
a. 函數(shù)指針變量不能進(jìn)行算術(shù)運(yùn)算,這是與數(shù)組指針變量不同的。數(shù)組指針變量加減一個(gè)整數(shù)可使指針移動(dòng)指向后面或前面的數(shù)組元素,而函數(shù)指針的移動(dòng)是毫無(wú)意義的。 b. 函數(shù)調(diào)用中"(*指針變量名)"的兩邊的括號(hào)不可少,其中的*不應(yīng)該理解為求值運(yùn)算,在此處它只是一種表示符號(hào)。
4. 指針型函數(shù)
前面我們介紹過(guò),所謂函數(shù)類型是指函數(shù)返回值的類型。 在C語(yǔ)言中允許一個(gè)函數(shù)的返回值是一個(gè)指針(即地址), 這種返回指針值的函數(shù)稱為指針型函數(shù)。
定義指針型函數(shù)的一般形式為:
類型說(shuō)明符 *函數(shù)名(形參表) { …… /*函數(shù)體*/ }
其中函數(shù)名之前加了“*”號(hào)表明這是一個(gè)指針型函數(shù),即返回值是一個(gè)指針。類型說(shuō)明符表示了返回的指針值所指向的數(shù)據(jù)類型。
如:
int *ap(int x,int y) { ...... /*函數(shù)體*/ }
表示ap是一個(gè)返回指針值的指針型函數(shù), 它返回的指針指向一個(gè)整型變量。下例中定義了一個(gè)指針型函數(shù) day_name,它的返回值指向一個(gè)字符串。該函數(shù)中定義了一個(gè)靜態(tài)指針數(shù)組name。name 數(shù)組初始化賦值為八個(gè)字符串,分別表示各個(gè)星期名及出錯(cuò)提示。形參n表示與星期名所對(duì)應(yīng)的整數(shù)。在主函數(shù)中, 把輸入的整數(shù)i作為實(shí)參, 在printf語(yǔ)句中調(diào)用day_name函數(shù)并把i值傳送給形參 n。day_name函數(shù)中的return語(yǔ)句包含一個(gè)條件表達(dá)式, n 值若大于7或小于1則把name[0] 指針?lè)祷刂骱瘮?shù)輸出出錯(cuò)提示字符串“Illegal day”。否則返回主函數(shù)輸出對(duì)應(yīng)的星期名。主函數(shù)中的第7行是個(gè)條件語(yǔ)句,其語(yǔ)義是,如輸入為負(fù)數(shù)(i<0)則中止程序運(yùn)行退出程序。exit是一個(gè)庫(kù)函數(shù),exit(1)表示發(fā)生錯(cuò)誤后退出程序, exit(0)表示正常退出。
應(yīng)該特別注意的是函數(shù)指針變量和指針型函數(shù)這兩者在寫法和意義上的區(qū)別。如int(*p)()和int *p()是兩個(gè)完全不同的量。int(*p)()是一個(gè)變量說(shuō)明,說(shuō)明p 是一個(gè)指向函數(shù)入口的指針變量,該函數(shù)的返回值是整型量,(*p)的兩邊的括號(hào)不能少。int *p() 則不是變量說(shuō)明而是函數(shù)說(shuō)明,說(shuō)明p是一個(gè)指針型函數(shù),其返回值是一個(gè)指向整型量的指針,*p兩邊沒(méi)有括號(hào)。作為函數(shù)說(shuō)明, 在括號(hào)內(nèi)最好寫入形式參數(shù),這樣便于與變量說(shuō)明區(qū)別。 對(duì)于指針型函數(shù)定義,int *p()只是函數(shù)頭部分,一般還應(yīng)該有函數(shù)體部分。
main(){ int i; char *day_name(int n); printf("input Day No:\n"); scanf("%d",&i); if(i<0) exit(1); printf("Day No:%2d-->%s\n",i,day_name(i)); } char *day_name(int n){ static char *name[]={ "Illegal day", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}; return((n<1||n>7) ? name[0] : name[n]); }
本程序是通過(guò)指針函數(shù),輸入一個(gè)1~7之間的整數(shù), 輸出對(duì)應(yīng)的星期名。指針數(shù)組的說(shuō)明與使用一個(gè)數(shù)組的元素值為指針則是指針數(shù)組。 指針數(shù)組是一組有序的指針的集合。 指針數(shù)組的所有元素都必須是具有相同存儲(chǔ)類型和指向相同數(shù)據(jù)類型的指針變量。
指針數(shù)組說(shuō)明的一般形式為: 類型說(shuō)明符*數(shù)組名[數(shù)組長(zhǎng)度]
其中類型說(shuō)明符為指針值所指向的變量的類型。例如: int *pa[3] 表示pa是一個(gè)指針數(shù)組,它有三個(gè)數(shù)組元素, 每個(gè)元素值都是一個(gè)指針,指向整型變量。通常可用一個(gè)指針數(shù)組來(lái)指向一個(gè)二維數(shù)組。 指針數(shù)組中的每個(gè)元素被賦予二維數(shù)組每一行的首地址, 因此也可理解為指向一個(gè)一維數(shù)組。圖6—6表示了這種關(guān)系。
int a[3][3]={1,2,3,4,5,6,7,8,9}; int *pa[3]={a[0],a[1],a[2]}; int *p=a[0]; main(){ int i; for(i=0;i<3;i++) printf("%d,%d,%d\n",a[i][2-i],*a[i],*(*(a+i)+i)); for(i=0;i<3;i++) printf("%d,%d,%d\n",*pa[i],p[i],*(p+i)); }
本例程序中,pa是一個(gè)指針數(shù)組,三個(gè)元素分別指向二維數(shù)組a的各行。然后用循環(huán)語(yǔ)句輸出指定的數(shù)組元素。其中a[i]表示i行0列元素值;(*(a+i)+i)表示i行i列的元素值;pa[i]表示i行0列元素值;由于p與a[0]相同,故p[i]表示0行i列的值;(p+i)表示0行i列的值。讀者可仔細(xì)領(lǐng)會(huì)元素值的各種不同的表示方法。 應(yīng)該注意指針數(shù)組和二維數(shù)組指針變量的區(qū)別。 這兩者雖然都可用來(lái)表示二維數(shù)組,但是其表示方法和意義是不同的。
二維數(shù)組指針變量是單個(gè)的變量,其一般形式中"(*指針變量名)“兩邊的括號(hào)不可少。而指針數(shù)組類型表示的是多個(gè)指針( 一組有序指針)在一般形式中”*指針數(shù)組名"兩邊不能有括號(hào)。例如: int (*p)[3];表示一個(gè)指向二維數(shù)組的指針變量。該二維數(shù)組的列數(shù)為3或分解為一維數(shù)組的長(zhǎng)度為3。 int *p[3] 表示p是一個(gè)指針數(shù)組,有三個(gè)下標(biāo)變量p[0],p[1],p[2]均為指針變量。
指針數(shù)組也常用來(lái)表示一組字符串, 這時(shí)指針數(shù)組的每個(gè)元素被賦予一個(gè)字符串的首地址。 指向字符串的指針數(shù)組的初始化更為簡(jiǎn)單。例如在例6.20中即采用指針數(shù)組來(lái)表示一組字符串。 其初始化賦值為:
char *name[]={"Illagal day", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
完成這個(gè)初始化賦值之后,name[0]即指向字符串"Illegal day",name[1]指?quot;Monday"…。
指針數(shù)組也可以用作函數(shù)參數(shù)。在本例主函數(shù)中,定義了一個(gè)指針數(shù)組name,并對(duì)name 作了初始化賦值。其每個(gè)元素都指向一個(gè)字符串。然后又以name 作為實(shí)參調(diào)用指針型函數(shù)day name,在調(diào)用時(shí)把數(shù)組名 name 賦予形參變量name,輸入的整數(shù)i作為第二個(gè)實(shí)參賦予形參n。在day name函數(shù)中定義了兩個(gè)指針變量pp1和pp2,pp1被賦予name[0]的值(即name),pp2被賦予name[n]的值即(name+ n)。由條件表達(dá)式?jīng)Q定返回pp1或pp2指針給主函數(shù)中的指針變量ps。最后輸出i和ps的值。
指針數(shù)組作指針型函數(shù)的參數(shù)
main(){ static char *name[]={ "Illegal day", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}; char *ps; int i; char *day_name(char *name[],int n); printf("input Day No:\n"); scanf("%d",&i); if(i<0) exit(1); ps=day_name(name,i); printf("Day No:%2d-->%s\n",i,ps); } char *day_name(char *name[],int n) { char *pp1,*pp2; pp1=*name; pp2=*(name+n); return((n<1||n>7)? pp1:pp2); }
下例要求輸入5個(gè)國(guó)名并按字母順序排列后輸出。在以前的例子中采用了普通的排序方法, 逐個(gè)比較之后交換字符串的位置。交換字符串的物理位置是通過(guò)字符串復(fù)制函數(shù)完成的。 反復(fù)的交換將使程序執(zhí)行的速度很慢,同時(shí)由于各字符串(國(guó)名) 的長(zhǎng)度不同,又增加了存儲(chǔ)管理的負(fù)擔(dān)。 用指針數(shù)組能很好地解決這些問(wèn)題。把所有的字符串存放在一個(gè)數(shù)組中, 把這些字符數(shù)組的首地址放在一個(gè)指針數(shù)組中,當(dāng)需要交換兩個(gè)字符串時(shí), 只須交換指針數(shù)組相應(yīng)兩元素的內(nèi)容(地址)即可,而不必交換字符串本身。程序中定義了兩個(gè)函數(shù),一個(gè)名為sort完成排序, 其形參為指針數(shù)組name,即為待排序的各字符串?dāng)?shù)組的指針。形參n為字符串的個(gè)數(shù)。另一個(gè)函數(shù)名為print,用于排序后字符串的輸出,其形參與sort的形參相同。主函數(shù)main中,定義了指針數(shù)組name 并作了初始化賦值。然后分別調(diào)用sort函數(shù)和print函數(shù)完成排序和輸出。值得說(shuō)明的是在sort函數(shù)中,對(duì)兩個(gè)字符串比較,采用了strcmp 函數(shù),strcmp函數(shù)允許參與比較的串以指針?lè)绞匠霈F(xiàn)。name[k]和name[ j]均為指針,因此是合法的。字符串比較后需要交換時(shí), 只交換指針數(shù)組元素的值,而不交換具體的字符串, 這樣將大大減少時(shí)間的開銷,提高了運(yùn)行效率。
現(xiàn)編程如下:
#include"string.h" main(){ void sort(char *name[],int n); void print(char *name[],int n); static char *name[]={ "CHINA","AMERICA","AUSTRALIA", "FRANCE","GERMAN"}; int n=5; sort(name,n); print(name,n); } void sort(char *name[],int n){ char *pt; int i,j,k; for(i=0;i 6. main函數(shù)的參數(shù) 前面介紹的main函數(shù)都是不帶參數(shù)的。因此main 后的括號(hào)都是空括號(hào)。實(shí)際上,main函數(shù)可以帶參數(shù),這個(gè)參數(shù)可以認(rèn)為是 main函數(shù)的形式參數(shù)。C語(yǔ)言規(guī)定main函數(shù)的參數(shù)只能有兩個(gè),習(xí)慣上這兩個(gè)參數(shù)寫為argc和argv。 因此,main函數(shù)的函數(shù)頭可寫為: main (argc,argv)C語(yǔ)言還規(guī)定argc(第一個(gè)形參)必須是整型變量,argv( 第二個(gè)形參)必須是指向字符串的指針數(shù)組。加上形參說(shuō)明后,main函數(shù)的函數(shù)頭應(yīng)寫為: main (argc,argv) int argv; char *argv[];或?qū)懗桑?main (int argc,char *argv[]) 由于main函數(shù)不能被其它函數(shù)調(diào)用, 因此不可能在程序內(nèi)部取得實(shí)際值。那么,在何處把實(shí)參值賦予main函數(shù)的形參呢? 實(shí)際上,main函數(shù)的參數(shù)值是從操作系統(tǒng)命令行上獲得的。當(dāng)我們要運(yùn)行一個(gè)可執(zhí)行文件時(shí),在DOS提示符下鍵入文件名,再輸入實(shí)際參數(shù)即可把這些實(shí)參傳送到main的形參中去。 DOS提示符下命令行的一般形式為: C:>可執(zhí)行文件名 參數(shù) 參數(shù)……; 但是應(yīng)該特別注意的是,main 的兩個(gè)形參和命令行中的參數(shù)在位置上不是一一對(duì)應(yīng)的。因?yàn)?main的形參只有二個(gè),而命令行中的參數(shù)個(gè)數(shù)原則上未加限制。argc參數(shù)表示了命令行中參數(shù)的個(gè)數(shù)(注意:文件名本身也算一個(gè)參數(shù)),argc的值是在輸入命令行時(shí)由系統(tǒng)按實(shí)際參數(shù)的個(gè)數(shù)自動(dòng)賦予的。 例如: 有命令行為: C:>E6 24 BASIC dbase FORTRAN 由于文件名E6 24本身也算一個(gè)參數(shù),所以共有4個(gè)參數(shù),因此argc取得的值為4。argv參數(shù)是字符串指針數(shù)組,其各元素值為命令行中各字符串(參數(shù)均按字符串處理)的首地址。 指針數(shù)組的長(zhǎng)度即為參數(shù)個(gè)數(shù)。數(shù)組元素初值由系統(tǒng)自動(dòng)賦予。 其表示代碼示例: main(int argc,char *argv){ while(argc-->1) printf("%s\n",*++argv); } 本例是顯示命令行中輸入的參數(shù)如果上例的可執(zhí)行文件名為e24.exe,存放在A驅(qū)動(dòng)器的盤內(nèi)。 因此輸入的命令行為: C:>a:e24 BASIC dBASE FORTRAN 則運(yùn)行結(jié)果為: BASIC dBASE FORTRAN 該行共有4個(gè)參數(shù),執(zhí)行main時(shí),argc的初值即為4。argv的4個(gè)元素分為4個(gè)字符串的首地址。執(zhí)行while語(yǔ)句,每循環(huán)一次 argv值減1,當(dāng)argv等于1時(shí)停止循環(huán),共循環(huán)三次, 因此共可輸出三個(gè)參數(shù)。在printf函數(shù)中,由于打印項(xiàng)*++argv是先加1再打印, 故第一次打印的是argv[1]所指的字符串BASIC。第二、 三次循環(huán)分別打印后二個(gè)字符串。而參數(shù)e24是文件名,不必輸出。 下例的命令行中有兩個(gè)參數(shù),第二個(gè)參數(shù)20即為輸入的n值。在程序中*++argv的值為字符串“20”,然后用函數(shù)"atoi"把它換為整型作為while語(yǔ)句中的循環(huán)控制變量,輸出20個(gè)偶數(shù)。 #include"stdlib.h" main(int argc,char*argv[]){ int a=0,n; n=atoi(*++argv); while(n--) printf("%d ",a++*2); } 本程序是從0開始輸出n個(gè)偶數(shù)。指向指針的指針變量如果一個(gè)指針變量存放的又是另一個(gè)指針變量的地址, 則稱這個(gè)指針變量為指向指針的指針變量。 在前面已經(jīng)介紹過(guò),通過(guò)指針訪問(wèn)變量稱為間接訪問(wèn), 簡(jiǎn)稱間訪。由于指針變量直接指向變量,所以稱為單級(jí)間訪。 而如果通過(guò)指向指針的指針變量來(lái)訪問(wèn)變量則構(gòu)成了二級(jí)或多級(jí)間訪。在C語(yǔ)言程序中,對(duì)間訪的級(jí)數(shù)并未明確限制, 但是間訪級(jí)數(shù)太多時(shí)不容易理解解,也容易出錯(cuò),因此,一般很少超過(guò)二級(jí)間訪。 指向指針的指針變量說(shuō)明的一般形式為: 類型說(shuō)明符** 指針變量名; 例如: int ** pp; 表示pp是一個(gè)指針變量,它指向另一個(gè)指針變量, 而這個(gè)指針變量指向一個(gè)整型量。下面舉一個(gè)例子來(lái)說(shuō)明這種關(guān)系。 main(){ int x,*p,**pp; x=10; p=&x; pp=&p; printf("x=%d\n",**pp); } 上例程序中p 是一個(gè)指針變量,指向整型量x;pp也是一個(gè)指針變量, 它指向指針變量p。通過(guò)pp變量訪問(wèn)x的寫法是**pp。程序最后輸出x的值為10。通過(guò)上例,讀者可以學(xué)習(xí)指向指針的指針變量的說(shuō)明和使用方法。 下述程序中首先定義說(shuō)明了指針數(shù)組ps并作了初始化賦值。 又說(shuō)明了pps是一個(gè)指向指針的指針變量。在5次循環(huán)中, pps 分別取得了ps[0],ps[1],ps[2],ps[3],ps[4]的地址值。再通過(guò)這些地址即可找到該字符串。 main(){ static char *ps[]={ "BASIC","DBASE","C","FORTRAN", "PASCAL"}; char **pps; int i; for(i=0;i<5;i++){ pps=ps+i; printf("%s\n",*pps); } } 本程序是用指向指針的指針變量編程,輸出多個(gè)字符串。 7. 本章小結(jié) 指針是C語(yǔ)言中一個(gè)重要的組成部分,使用指針編程有以下優(yōu)點(diǎn): (1)提高程序的編譯效率和執(zhí)行速度。 (2)通過(guò)指針可使用主調(diào)函數(shù)和被調(diào)函數(shù)之間共享變量或數(shù)據(jù)結(jié)構(gòu),便于實(shí)現(xiàn)雙向數(shù)據(jù)通訊。 (3)可以實(shí)現(xiàn)動(dòng)態(tài)的存儲(chǔ)分配。 (4)便于表示各種數(shù)據(jù)結(jié)構(gòu),編寫高質(zhì)量的程序。 指針的運(yùn)算 (1)取地址運(yùn)算符&:求變量的地址 (2)取內(nèi)容運(yùn)算符*:表示指針?biāo)傅淖兞?(3)賦值運(yùn)算 ·把變量地址賦予指針變量 ·同類型指針變量相互賦值 ·把數(shù)組,字符串的首地址賦予指針變量 ·把函數(shù)入口地址賦予指針變量 (4)加減運(yùn)算 對(duì)指向數(shù)組,字符串的指針變量可以進(jìn)行加減運(yùn)算,如p+n,p-n,p++,p--等。 對(duì)指向同一數(shù)組的兩個(gè)指針變量可以相減。對(duì)指向其它類型的指針變量作加減運(yùn)算是無(wú)意義的。 (5) 關(guān)系運(yùn)算 指向同一數(shù)組的兩個(gè)指針變量之間可以進(jìn)行大于、小于、 等于比較運(yùn)算。指針可與0比較,p==0表示p為空指針。 與指針有關(guān)的各種說(shuō)明和意義見下表。 int *p; p為指向整型量的指針變量 int *p[n]; p為指針數(shù)組,由n個(gè)指向整型量的指針元素組成。 int (*p)[n]; p為指向整型二維數(shù)組的指針變量,二維數(shù)組的列數(shù)為n int *p() p為返回指針值的函數(shù),該指針指向整型量 int (*p)() p為指向函數(shù)的指針,該函數(shù)返回整型量 int **p p為一個(gè)指向另一指針的指針變量,該指針指向一個(gè)整型量。 有關(guān)指針的說(shuō)明很多是由指針,數(shù)組,函數(shù)說(shuō)明組合而成的。 但并不是可以任意組合,例如數(shù)組不能由函數(shù)組成,即數(shù)組元素不能是一個(gè)函數(shù);函數(shù)也不能返回一個(gè)數(shù)組或返回另一個(gè)函數(shù)。例如 int a5;就是錯(cuò)誤的。 關(guān)于括號(hào) 在解釋組合說(shuō)明符時(shí), 標(biāo)識(shí)符右邊的方括號(hào)和圓括號(hào)優(yōu)先于標(biāo)識(shí)符左邊的“*”號(hào),而方括號(hào)和圓括號(hào)以相同的優(yōu)先級(jí)從左到右結(jié)合。但可以用圓括號(hào)改變約定的結(jié)合順序。 閱讀組合說(shuō)明符的規(guī)則是“從里向外”。 從標(biāo)識(shí)符開始,先看它右邊有無(wú)方括號(hào)或園括號(hào),如有則先作出解釋,再看左邊有無(wú)*號(hào)。 如果在任何時(shí)候遇到了閉括號(hào),則在繼續(xù)之前必須用相同的規(guī)則處理括號(hào)內(nèi)的內(nèi)容。例如: int*(*(*a)())[10] ↑ ↑↑↑↑↑↑ 7 6 4 2 1 3 5 上面給出了由內(nèi)向外的閱讀順序,下面來(lái)解釋它: (1)標(biāo)識(shí)符a被說(shuō)明為; (2)一個(gè)指針變量,它指向; (3)一個(gè)函數(shù),它返回; (4)一個(gè)指針,該指針指向; (5)一個(gè)有10個(gè)元素的數(shù)組,其類型為; (6)指針型,它指向; (7)int型數(shù)據(jù)。 因此a是一個(gè)函數(shù)指針變量,該函數(shù)返回的一個(gè)指針值又指向一個(gè)指針數(shù)組,該指針數(shù)組的元素指向整型量。 C 語(yǔ)言 數(shù)據(jù)結(jié)構(gòu)
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。