您好,登錄后才能下訂單哦!
相信大家對下面的代碼不陌生:
int i=2; int *p; p=&i;
這是最簡單的指針應用,也是最基本的用法。再來熟悉一下什么是指針:首先指針是一個變量,它保存的并不是平常的數據,而是變量的地址。如上代碼,指針p中保存的是整型變量i的地址信息。
接下來看如何定義一個指針,既然指針也是一個變量,那么它的定義也和其它變量一樣定義:如:int p;是間接尋址或間接引用運算符。上例中我們還看到了一個特別的運算符&,它是一個取地址運算符(在其他合適場合&也是按位運算運算符,&&為取交集運算符)。
在上面的指針定義中,我們看到了定義的是一個整型指針,難道指針還有類型嗎?答案是肯定的,指針只能指向某種特定類型的對象,也就是說,每個指針都必須指向某種特定的數據類型(唯一的例外:指向void類型的指針可以存放指向任何類型的指針,但它不能間接引用其自身。)。比如,int 類型的指針絕對不能指向char 類型的變量。
下面我們給出一個完整的例子來說明指針的簡單應用:
#include<stdio.h>void main() { int a,b,c,*p; a=1; b=3; p=&a; b=*p+1; c=*(p+1); printf("%d %d %d %d /n",a,b,c,*p+3); }
運行結果為: 1 2 -858993460 4
這是個完整的例子,可以自己在機器上調試一下,現在很多人用的都是微軟的Visual Studio 開發環境,有人就不知道在該開發環境中怎么寫C程序以及調試C程序,具體境況可以參考附錄。
在上面例子中,看到了這樣兩個表達式b=p+1;和c=(p+1);前者的意思是p所指的地址里的內容加1再賦給b,相當于b=a+1;,后者是p所指的地址加1再把(p+1)所指的地址賦給c,當然我們不知道p的下一個地址里放的是什么,所以輸出了一個隨機值(這樣的操作時很危險的,切記不要使用不確定的內存地址)。
數組大家應該都很熟悉了,用途非常廣泛。
int a[4]={2,4,5,9};
此語句定義一個4個空間大小的整型數組a并為它進行了初始化。
數組的基礎知識可以參考其他相應的教材,我們在這主要討論指針和數組的結合應用。
我們再來看個完整的例子:
#include<stdio.h>void main(){ int a[4]={2,4,5,9}; int *p; p=a; *p=*p++; printf("%d %d %d/n",*p,*p+6,*(p+1)); }
運行結果:4 10 5
分析:語句p=a;表示把數組a的第0個元素的地址賦給指針p,數組名a代表的是數組a的第0個元素的地址。
a[i]表示數組a的第i個元素,如果定義一個指針p,那么語句p=&a[0];表示可以將指針p指向數組a的第0個元素,也就是說p的值為數組元素a[0]的地址。那么(p+1)引用的是數組元素a[1]的內容,p+i是數組元素a[i]的地址,(p+i)引用的是數組元素a[i]的內容。對數組元素a[i]的引用也可以寫成(a+i)。可以得出結論:&a[i]與a+i的含義相同,p[i]與(p+i)也是等價的。
雖然數組和指針有這么多通用的地方,但我們必須記住,數組名和指針之間有一個不同之處。指針是一個變量,因此語句p=a和p++都是合法的。但數組名不是變量,因此,類似于a=p和a++形式的語句是非法的。
下面來看一個我們常用的函數strlen(char *s):
int strlen(char *s){ int n; for(n=0;*s!='/0';s++) n++; return n; }
因為s是一個指針,所以對其執行自增運算是合法的。執行s++運算不會影響到strlen函數的調用者中的字符串,它僅對該指針在strlen函數中的私有副本進行自增運算。在函數定義中,形式參數char s[]和char *s是等價的。
我們再來看一下地址算術運算:如果p是一個指向數組中某個元素的指針,那么p++將對p進行自增運算并指向下一個元素,而p+=i將對p進行加i的增量運算,使其指向指針p當前所指向元素之后的第i個元素。同其他類型的變量一樣,指針也可以進行初始化。通常,對指針有意義的初始化值只能是0或者是表示地址的表達式,對后者來說,表達式所表達的地址必須是在此之前已定義的具有適當類型的數據的地址。任何指針與0進行相等或者不相等的比較運算都有意義。但是指向不同數組的元素的指針之間的算術或比較運算沒有意義。指針還可以和整數進行相加或相減運算。如p+n表示指針p當前指向的對象之后第n個對象的地址。無論指針p指向的對象是何種類型,上述結論都成立。在計算p+n時,n將根據p指向的對象的長度按比例縮放,而p指向的對象的長度則取決于p的聲明。例如,如果int類型占4個字節的存儲空間,那么在int類型的計算中對應的n將按4的倍數來計算。
指針的減法運算也是有意義的,如果p和q指向相同數組中的元素,且p<q,那么q-p+1就是位于p和q指向的元素之間的元素的數目。我們來看一下strlen(char *s)的另一個版本:
int strlen(char *s){ char *p=s; while(*p!='/0') p++; return p-s; }
程序中,p被初始化為指向s,即指向該字符串的第一個字符,while循環語句將依次檢查字符串中的每個字符,直到遇到標識字符數組結尾的字符’/0’為止。由于p是指向字符的指針,所以每執行以此p++,p就將指向下一個字符的地址,p-s則表示已經檢查過的字符數,即字符串長度。
總結:有效的指針運算包括相同類型指針之間的賦值運算;指針和整數之間的加減運算;指向相同數組中元素的兩個指針間的減法或比較運算;將指針賦值為0或指針與0之間的比較運算。其他所有形式的指針運算都是非法的。
再來看兩條語句:
char a[]=”I am a boy”; char *p=”I am a boy”;
a是一個僅僅足以存放初始化字符串以及空字符’/0’的一維數組。數組中的單個字符可以進行修改,但a始終指向同一個存儲位置。而p是一個指針,其初值指向一個字符串常量,之后它可以被修改以指向其他地址,但如果試圖修改字符串的內容,結果是沒有定義的。
為了更容易理解數組和指針的關系,我們再來看一個函數:
void strcpy(char *s,char *t){ int i; i=0; while((s[i]=t[i])!='/0') i++; }
因為參數是通過值傳遞的,所以在strcpy函數中可以以任何方式使用參數s和t。
下面是指針實現的幾個版本:
void strcpy(char *s,char *t){ while((*s=*t)!='/0'){ s++; t++; } }
最簡版本:
void strcpy(char *s,char *t){ while(*s++=*t++) ; }
這里,s和t的自增運算放到了循環的測試部分中。表達式*t++的值是執行自增運算之前t所指向的字符。后綴運算符++表示在讀取該字符之后才改變t的值。同樣,在s執行自增運算之前,字符就被存儲到了指針s指向的舊位置。上面的版本中表達式同’/0’的比較是多余的,因為只需要判斷表達式的值是否為0即可。
這兩個詞次聽起來挺新穎的,到底是什么意思呢?
由于指針本身也是變量,所以它們也可以像其他變量一樣存儲在數組中。這一點很容易理解。
#include<stdio.h>#include<string.h>void main(){ int i; char b[]={"wustrive_2008"}; char *a[1]; *a=b; for(i=0;i<strlen(b);i++) printf("%c",*(a[0]+i)); printf("/n"); }
運行結果:wustrive_2008
這里庫函數strlen,strlen為string類的標準庫函數,所以要包含#include。
下面我們來自己寫一個strlen函數,我們把上面的例子該成這樣:
#include<stdio.h>int strlen(char *s){ char *p=s; while(*p!='/0') p++; return p-s; }void main(){ int i; char b[]={"wustrive_2008"}; char *a[1]; *a=b; for(i=0;i<strlen(b);i++) printf("%c",*(a[0]+i)); printf("/n"); }
這個運行結果和上個例子一樣,不一樣的只是我們自己實現了strlen函數,我們再編程時使用的庫函數,都是語言的開發者或者系統為我們寫好了的函數,其實我們也可以自己寫。
這個例子很好的演示了指針數組的用法,指針數組a的值a[1]是一個指針,指向字符數組第一個字符。
指針的指針也很好理解,就是一個指針里放的是另一個指針的地址,而另一個指針可能指向一個變量的地址,還可能指向另一個指針。
看兩個定義語句:int a[5][10]; int *b[5];
從語法角度講,a[3][4]和b[3][4]都是對一個int對象的合法引用。但a是一個真正的二維數組,它分配了50個int類型長度的存儲空間。但b定義僅僅分配了5個指針,并且沒有初始化,它們必須進行顯示的初始化,假設b的每個元素都指向一個有10個元素的數組,那么編譯器就要為它分配50個int類型長度的存儲空間以及5個指針存儲空間。指針數組的一個重要優點在于,數組的每一行長度可以不同,也就是說,b的每個元素不必都指向一個有10個元素的向量。
在C語言中,函數雖然不是變量,但可以定義指向函數的指針。這種類型的指針可以被賦值,存放在數組中,傳遞給函數以及作為函數的返回值等。
如果下面的語句為一個函數的參數,表示什么意思:
int (p)(void ,void *)
它表明p是一個指向函數的指針,該函數具有兩個void類型的參數,其返回值類型為int。語句if((p)(v[i],v[left])<0)中,p的使用和其聲明是一致的,p是一個指向函數的指針,p代表一個函數。如果寫成這樣:int p(void ,void )則表明p是一個函數,該函數返回一個int類型的指針。
下面來看兩個聲明:
int *f(); //f是一個函數,它返回一個指向int類型的指針int (*pf)(); //pf是一個指向函數的指針,該函數返回一個int類型的對象。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。