*p++移動的byte數

不同數據類型的變量,佔用的字節數不同,系統把變量佔據存儲單元的第一個字節的地址作爲該變量的地址

⑴ 間接訪問運算

用變量名對其所對應的存儲單元的內容進行讀寫稱爲直接訪問,而通過存儲單元的地址對其內容進行讀寫的則稱爲間接訪問。儘管指針變量中保存的是存儲單元的地址,而引入指針的目的主要是爲了更方便快捷地訪問存儲單元的內容。間接訪問是在引用的指針變量前面加一個“*”號,用來表示指針所指向的存儲單元的值或內容。

需要說明的是:在定義指針變量和在引用時“*”的含義是不同的。【int a=5, *p】中的“*”表示所定義的p是一個指針變量,而在語句printf("%d", *p)中的*p則是間接訪問,表示指針變量p所指向的存儲單元的內容。由於指針的間接訪問是訪問存儲單元的內容,所以語句*p=&a在編譯時也將出現警告錯誤。

⑵ 指針變量加或減一個整型量,從而得到另一個地址,當然自增自減運算也是合法的。例如當指針變量p指向一個一維數組的首地址,則p+n表示的是下標爲n的元素地址。指針變量乘除一個整型量無意義,C語言也不允許此類語句出現。

⑶ 由於指針變量中的地址也是一數值,所以指針變量間也可以進行關係運算。

⑷ 兩個類型相同的指針變量可以相減,例如指向同一數組的指針變量相減可以得到兩個指針間元素的個數。相加或相乘則無意義。

由於++與*優先級相同,且均爲自右至左結合,所以當用間接訪問形式使得所指變量自加或自減時,應使用括號。例如:指針變量p已指向變量a,用間接訪問形式使得變量a自加1,應寫爲(*p)++,即等價於a++,但不能寫成*p++,*p++是後面要介紹的一種指針運算,所以必須要分開。

由於數組佔據一塊連續的存儲單元,且數組中的各元素的相對位置總是固定的,所以對數組元素的引用除了使用下標外,還可以使用指針運算來實現。

由於C語言中的一維數組名代表數組的首地址,即數組的第一個元素所在存儲單元的地址,所以&a[0]與a是等價的,p=&a[0]也可寫爲p=a。

按照C語言的規定,當指針變量p指向數組中的某一元素時,p+1則指向下一個元素,p+n指向後面第n個元素;同樣,p-1指向前一個元素,而p-n則指向前面第n個元素。當指針移動1,系統內部移動的字節數,取決於指針變量p的基類型。若爲字符型則指針移動1個字節,若爲整型,則指針移動兩個字節,依此類推。

當p指向數組a的首地址時,表示數組元素a[i]有四種形式:a[i]    * (a+i)    *(p+i)     p[i]

需要說明的是:指針變量與數組名相比,可以進行自加自減或賦值運算。例如p++或p=p+n,它們分別表示指針變量p指向下一個元素和指向後面第n個元素。而數組名一旦定義,則所代表的地址是不能改變的。雖然*(a+i)也能訪問數組中每個元素,但它是通過i的變化來實現的。

由於a[i]可以看作是一維數組名,所以它代表該行的首地址,因此,二維數組a中的任一元素的地址既可以通過&a[i][j]求得,也可以通過a[i]+j求得,即&a[i][j]與a[i]+j等價在一維數組的討論中,a[i]與*(a+i)等價。因此,若將a[i]+j中的a[i]用*(a+i)代換,則二維數組元素的地址可用*(a+i)+j表示,相應的數組元素表示爲*(*(a+i)+j)

值得注意的是:若地址表示法*(a+i)+j中的i,j均爲0,則該表達式簡化爲*a,表示a[0][0]的地址。雖然在C語言中a和*a所代表的物理地址值都是相同的,都是二維數組第一個元素的地址;但是從邏輯上來分析,*a表示元素a[0][0]的地址,而a表示a[0]的地址(在這裏a[0]爲二維數組中的第一行的一維數組),二者的含義是不同的。*a+1表示元素a[0][1]的地址,或稱爲列地址,即加1只移動一個元素;而a+1則表示一維數組a[1]的地址,或稱爲行地址,即加1則移動一行元素。作爲基類型爲簡單類型的指針變量只能指向具體元素的地址(列地址),而不能指向二維數組的行地址

由於C語言中的二維數組元素是以行優先連續存儲的,且在內存中元素的存儲仍然是線性的,因此可以把二維數組作爲一維數組來處理。若一個指針變量p已指向二維數組的第一個元素,那麼 i行j列元素的地址可表示爲p+i*n+j,而元素的值爲*(p+i*n+j),也可以使用p++這樣的語句逐一訪問二維數組的元素。

爲了便於訪問二維數組,C語言中還專門設置了指向由n個元素組成的一維數組的指針。定義格式爲:

類型 (*指針名)[常量表達式]。 例如 :int  (*p)[4],a[3][4];

由於括號的存在,*首先與p結合,說明p是一個指針變量再與[]結合,說明它指向包含4個整型元素的一維數組。在這裏不能省略“()”,因爲省略括號後則變成*p[],由於“[]”的優先組高於“*”,所以定義的不再是指向數組的指針變量,而是指針數組

類型 (*指針名)[常量表達式]這種指針變量只能指向一維數組。p+1指向的是下一個一維數組。即指針移動的不是一個元素,而是一行元素。因此,這種類型的指針變量和二維數組名的作用是相同的。若有p=a,則i行j列的元素地址爲*(p+i)+j,即a[i][j]與*(*(p+i)+j)等效,表示形式與數組名錶示法相同。

在C語言中字符串是存儲在字符數組中的字符數組與指針的關係與一維數組與指針的關係基本相同,只是數組與指針均爲字符型。當定義一個字符型的指針變量並把它指向一字符數組時,就可以通過指針變量來處理字符串了。

除此之外,字符指針變量還可以指向字符串常量,這是其它類型的指針所不具備的。例如:

char *string="I love my Motherland!";

char *string;

string="I love my Motherland!"

C語言對字符串常量是按字符數組處理的,在內存開闢了一個字符數組用來存放字符串常量。由於指針變量只能保存地址,所以賦給字符指針變量的不是字符串自身,而是字符串的首地址

例7.12  用字符指針實現字符串的複製。

main()

{

char *a="I love my Motherland !",b[40], *p1, *p2;

p1=a;

p2=b;

printf("%s",p1);

while(*p1)

*p2++=*p1++;

*p2='/0';

printf("%s",b);

}

在例7.12中使用的是字符指針,雖然源字符串可以用指針變量定義,但目標字符串必須用字符數組來定義。因爲指針變量只能定義一個保存字符串首地址的指針,而沒有保存字符的空間。如:

main()

{

char *a="I love my Motherland !", *b, *p1, *p2;

p1=a;

p2=b;

printf("%s",p1);

while(*p1)

*p2++=*p1++;

*p2='/0';

printf("%s",b);

}是錯誤的,有可能造成系統崩潰。

當然該程序還可以寫得更簡潔些:

main()

{

char *a="I love my Motherland !",b[40], *p1, *p2;

p1=a;

p2=b;

printf("%s",p1);

while(*p2++=*p1++);

printf("%s",b);

}

雖然字符數組和字符指針變量都能實現對字符串的存儲和運算,但二者有本質的區別。

⑴ 字符數組只能在初始化時賦初值,而不能在語句中賦值。例如:

char a[]="I love my Motherland!";

而不能

 char a[30];

 a="I love my Motherland!";

字符指針變量不僅可以初始化,也可以在語句中爲其賦值。如:

char *a="I love my Motherland!";

又可以

char *a;

a="I love my Motherland!";

⑵ 字符數組既有確定的首地址,也有存儲字符的空間;而字符指針變量只能保存一個字符串的首地址,在未指向具體字符串或字符數組之前,是沒有保存字符的空間的。如:

char *t;

scanf("%s",t);

是錯誤的,有可能造成系統崩潰。

程序實例:

例7.13  將字符數組a中的ASCII碼爲奇數的字符複製到b數組中去。

main()

{

char a[40]= "I love my Motherland! ",b[40], *p1, *p2;

p1=a;

p2=b;

while (*p1!= '/0')

{

if(*p1%2==1) *p2++= *p1++;

else p1++;

}

*p2='/0';

printf("%s",b);

}

例7.14  將字符數組a中的“*”號刪除。

main()

{

char a[40]= "*I* love* my Mothland! **** ",*p1, *p2;

p1=p2=a;

while (*p1!= '/0')

{

if(*p1!= '*') *p2++= *p1++;

else p1++;

}

*p2='/0';

printf("%s",a);

}

用字符指針變量還可以指向一個格式字符串,替代標準輸入輸出函數中的格式字符串。如:

char * format1="%d%d",*format2="a=%d,b=%d";

int a,b;

scanf(format1,&a,&b);

printf(format2,a,b);

指針數組與前面學過的數組一樣,只不過數組的元素是指針類型。指針數組通常用來處理字符串數組或數據結構中的十字鏈表等

定義指針數組的格式爲:數據類型  *數組名[常量表達式]

例如: char *c[10]; 定義了一個指針數組c,它有10個元素,數組元素的數據類型爲字符型。也就是指針數組中的元素都是一個字符型指針變量。指針數組與指向數組的指針的定義格式很相近,不可混淆。

例7.15  用指針數組輸出字符串數組。

main()

{

char *day_table[]={"Sun","Mon","Tues","Wednes", "Thurs","Fri","Satur"};

int i;

for(i=0;i<7;i++)

printf("%s/n",day_table[i]);

}

程序中使用字符指針直接定義字符串,當然也可以用二維字符數組定義。雖然用字符數組定義需按最長的字符串指定列數,會浪費一些存儲空間,但在實際編程中則更加實用。

例7.16  將多個字符串排序後輸出。

#include<string.h>

main()

{

char str[][15]={ "Visual Basic","Visual Foxpro","Java","C","Visual C",};

char *name[5], *s;

int i,j,k;

for(i=0;i<5;i++)

name[i]=str[i];

for(i=0;i<4;i++)

{

k=i;

for(j=i+1;j<5;j++)

if(strcmp(name[k],name[j])>0) k=j;

if(k!=i)

{

s=name[i]; name[i]=name[k]; name[k]=s;

}

}

for(i=0;i<5;i++)

printf("/n%s",name[i]);

}

程序中採用了選擇排序法對各字符串進行排序。但這種排序不是將字符串交換存儲位置,因爲每個字符串中有多個字符,交換起來既費時又費力;而是通過修改指針的指向進行排序,實現起來既方便,效率也高。對於字符串比較函數strcmp,是對兩個字符串的比較,也就是說首先比較兩個字符串的第一個字符,若不相等則結束比較;否則比較兩個字符串的第二個字符,直到遇到一個字符串的結束標誌。

指向指針的指針

指針數組是通過其下標訪問元素的,若使用另一個指針來引用指針數組中的元素,則這個指針就是指向指針的指針。

定義指向指針的指針格式爲:類型 **指針變量名

例如:char **p; 由於“*”運算符的結合性是從右至左,**p相當於*(*p),括號內的表示字符型的指針變量,而括號外的“*”則表示該指針變量指向的是字符型指針變量,即爲指向字符型指針的指針

例7.17  用指向指針的指針改寫例題7.16。

#include<string.h>

main()

{

char str[][15]={ "Visual Basic","Visual Foxpro","Java","C","Visual C",};

char *name[5], *s, **p1, **p2, **p;

int i,j,k;

for(i=0;i<5;i++)

name[i]=str[i];

for(p1=name;p1<name+4;p1++)

{

for(p=p1,p2=p1+1;p2<name+5;p2++)

if(strcmp(*p, *p2)>0) p=p2;

if(p!=p1)

{

s=*p; *p=*p1; *p1=s;

}

}

for(p=name;p<name+5;)

printf("/n%s", *p++);

}

例7.18  用指向指針的指針輸出整型數組元素。

main()

{

int a[]={1,2,3,4,5,6,7,8,9,10},i;

int *num[10], **p;

for(i=0;i<10;i++)

num[i]=&a[i];

for(p=num;p<num+10;)

printf("%4d",**p++);

}

該例題只是爲了說明指向指針的指針的用法,實際上它與一維數組與指針的關係是一致的。

注意的問題

⑴ 不同類型的指針變量定義形式不同。

如有以下定義:int *p1, (*p2)[10], **p3;

定義中的p1爲指針變量;p2則爲指向一維數組的指針變量,且一維數組的元素個數爲10,在這裏不可省略圓括號;p3爲指向指針的指針變量。

⑵ 不能引用沒有賦值的指針變量,否則可能會造成系統癱瘓。如:

int *p1;

char *p2;

scanf("%d",p1);

scanf("%s",p2);

是錯誤的。因爲只定義了整型和字符型指針變量,沒有接收數據的空間。

 數據類型相同且指針類型相同的指針變量可以相互賦值。如有以下定義:

int *p1,(*p2)[10], **p3;

下列賦值語句

p1=p2;

p1=p3;

p3=p1;

p2=p1;

p2=p3;

均是不合法的。

⑷ 除了0之外,常量不能爲指針變量賦值,因爲變量或數組分配的存儲單元是由系統完成的。用0爲指針變量賦值,表示指針變量指向空,即不指向任何存儲單元。

 

參考文獻:http://www.17xie.com/read-272486.html

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