5、陣列和指標的關係
陣列的陣列名其實可以看作乙個指標。看下例:
例九:
intarray[10]=,value;
value=array[0]; //也可寫成:value=*array;
value=array[3]; //也可寫成:value=*(array+3);
value=array[4]; //也可寫成:value=*(array+4);
上例中,一般而言陣列名array代表陣列本身,型別是int[10],但如果把array看做指標的話,它指向陣列的第0個單元,型別是int* ,所指向的型別是陣列單元的型別即int。因此array等於0就一點也不奇怪了。同理,array+3是乙個指向陣列第3個單元的指標,所以(array+3)等於3。其它依此類推。
例十:
char *str[3]=;
chars[80];
strcpy(s,str[0]); //也可寫成strcpy(s,*str);
strcpy(s,str[1]); //也可寫成strcpy(s,*(str+1));
strcpy(s,str[2]); //也可寫成strcpy(s,*(str+2));
上例中,str是乙個三單元的陣列,該陣列的每個單元都是乙個指標,這些指標各指向乙個字串。把指標陣列名str當作乙個指標的話,它指向陣列的第0號單元,它的型別是char *,它指向的型別是char 。
str也是乙個指標,它的型別是char ,它所指向的型別是char,它指向的位址是字串」hello,thisisasample!」的第乙個字元的位址,即』h』的位址。注意:字串相當於是乙個陣列,在記憶體中以陣列的形式儲存,只不過字串是乙個陣列常量,內容不可改變,且只能是右值.如果看成指標的話,他即是常量指標,也是指標常量.
常量指標: 該指標是乙個常量,不可改變,指向某個位址之後就不能改變了,但他所指向的單元是可以改變的,很容易與指標常量弄混,所以一般讀的時候讀成常量指向,從字面上看就是乙個常量指向某個位址.
指標常量說明該指標所指向的是內容不可改變,但其自身是乙個變數,可以改變指向的內容,讀的時候讀成指向常量,從字面上看就是指向某個常量
str+1也是乙個指標,它指向陣列的第1號單元,它的型別是char**,它指向的型別是char*。
(str+1)也是乙個指標,它的型別是char,它所指向的型別是char,它指向 「hi,goodmorning.」的第乙個字元』h』
下面總結一下陣列的陣列名(陣列中儲存的也是陣列)的問題:
宣告了乙個陣列type array[n],則陣列名稱array就有了兩重含義:第一,它代表整個陣列,它的型別是type[n];第二 ,它是乙個常量指標,該指標的型別是type*,該指標指向的型別是type,也就是陣列單元的型別,該指標指向的記憶體區就是陣列第0號單元,該指標自己占有單獨的記憶體區,注意它和陣列第0號單元佔據的記憶體區是不同的。該指標的值是不能修改的,即類似array++的表示式是錯誤的。
在不同的表示式中陣列名array可以扮演不同的角色。
在表示式sizeof(array)中,陣列名array代表陣列本身,故這時sizeof函式測出的是整個陣列的大小。
在表示式*array中,array扮演的是指標,因此這個表示式的結果就是陣列第0號單元的值。sizeof(*array)測出的是陣列單元的大小。
表示式array+n(其中n=0,1,2,…..)中,array扮演的是指標,故array+n的結果是乙個指標,它的型別是type *,它指向的型別是type,它指向陣列第n號單元。故sizeof(array+n)測出的是指標型別的大小。在32位程式中結果是4。
例十一:
int array[10];
int (*ptr)[10];
ptr=&array;:
上例中ptr是乙個指標,它的型別是int(*)[10],他指向的型別是int[10] ,我們用整個陣列的首位址來初始化它。在語句ptr=&array中,array代表陣列本身。
本節中提到了函式sizeof(),那麼我來問一問,sizeof(指標名稱)測出的究竟是指標自身型別的大小呢還是指標所指向的型別的大小?答案是前者。例如:
int(*ptr)[10];
則在32位程式中,有:
sizeof(int(*)[10])==4
sizeof(int[10])==40
sizeof(ptr)==4
實際上,sizeof(物件)測出的都是物件自身的型別的大小,而不是別的什麼型別的大小。
6、指標和結構型別的關係
可以宣告乙個指向結構型別物件的指標。
例十二:
struct mystruct
; //宣告了結構物件ss,並把ss的成員初始化為20,30和40。
struct mystruct ss=;
//宣告乙個指向結構物件ss的指標。它的型別是mystruct*,它指向的型別是mystruct。
struct mystruct *ptr=&ss;
//宣告乙個指向結構物件ss的指標。但是pstr和它被指向的型別ptr是不同的。
int pstr=(int)&ss;
請問怎樣通過指標ptr來訪問ss的三個成員變數?
答案:
ptr->a; //指向運算子,或者可以這們(*ptr).a,建議使用前者
ptr->b;
ptr->c;
又請問怎樣通過指標pstr來訪問ss的三個成員變數?
答案:
*pstr; //訪問了ss的成員a。
*(pstr+1); //訪問了ss的成員b。
*(pstr+2) //訪問了ss的成員c。
雖然我在我的msvc++6.0上調式過上述**,但是要知道,這樣使用pstr來訪問結構成員是不正規的,為了說明為什麼不正規,讓我們看看怎樣通過指標來訪問陣列的各個單元: (將結構體換成陣列)
例十三:
int array[3]=;
int *pa=array;
通過指標pa訪問陣列array的三個單元的方法是:
*pa; //訪問了第0號單元
*(pa+1); //訪問了第1號單元
*(pa+2); //訪問了第2號單元
從格式上看倒是與通過指標訪問結構成員的不正規方法的格式一樣。
所有的c/c++編譯器在排列陣列的單元時,總是把各個陣列單元存放在連續的儲存區里,單元和單元之間沒有空隙。但在存放結構物件的各個成員時,在某種編譯環境下,可能會需要字對齊或雙字對齊或者是別的什麼對齊,需要在相鄰兩個成員之間加若干個」填充位元組」,這就導致各個成員之間可能會有若干個位元組的空隙。
所以,在例十二中,即使pstr訪問到了結構物件ss的第乙個成員變數a,也不能保證(pstr+1)就一定能訪問到結構成員b。因為成員a和成員b之間可能會有若干填充位元組,說不定*(pstr+1)就正好訪問到了這些填充位元組呢。這也證明了指標的靈活性。要是你的目的就是想看看各個結構成員之間到底有沒有填充位元組,嘿,這倒是個不錯的方法。
不過指標訪問結構成員的正確方法應該是象例十二中使用指標ptr的方法。
C語言指標學習三
因為指標和位址操作有關,先從位址匯流排說起。上節提到計算機cpu操作記憶體中的資料具體操作控制哪個記憶體單元是由位址匯流排控制。目前,大多數電腦cpu和記憶體條之間一般有32根位址匯流排 32跟位址匯流排就控制了2的32次方個記憶體單元。每個記憶體單元又是8個位元位,實際上32根位址匯流排控制的記憶...
C語言筆記(三)函式 指標
函式,相當於把大的任務拆分成小的模組,一般乙個函式不超過80行 每個程式只有乙個主函式 輸出資料只能是乙個。有多個返回值的時候可以使用乙個引數 函式宣告 只寫函式頭,不寫函式體 在函式宣告時,可以省略引數列表的引數名,只寫引數型別 傳值方式,在函式呼叫時,把實參值的乙份拷貝,賦值給形參 可以寫乙個例...
C語言指標(三) union C語言的棄兒
union作為c語言的乙個關鍵字跟關鍵字volatile一樣很少出現在程式設計師 的視野之中,當然相比於volatile,union的處境相對還好一點。但是我總覺得他是c語言的棄兒。那麼union與指標有什麼關係呢?答案是有,我們都知道union的成員變數是共享同一塊記憶體的,所以我們在使用unio...