1、
int a[3] = ;
int* p = a;
把陣列名賦值給指標表示將陣列的首元素的位址賦予此指標。
2、
int a[3] = ;
int* p = &a[0];
a[0]是a陣列的首元素,而&則是取位址運算子,所以「 &a[0]」取得的同樣是a陣列的首元素的位址,因此這段**的含義和**段是一致的。
3、
char * c1 = "hello";
char c2[6] = "world";
這兩句不都是宣告乙個字串嗎?有什麼區別嗎?
"hello"是乙個字串,然後讓char指標c1指向這個字串的首元素的位址。
第二句是宣告乙個長度為6的char型別陣列,並且設定陣列的初始值為"world"。注意末尾還有乙個隱藏的「/0」,所以長度是6,而不是5。
4、陣列指標的加減運算
對於指向陣列的指標變數可以進行加減運算,比如對於指向陣列的指標p,p++、p--、p+2等都是合法的。這裡的加減運算並不是針對陣列元素的,而是針對指標位置的,比如p當前指在首元素上,那麼p++後就指在第二個元素上;比如p當前指在第5個元素上,那麼p=p-2後,p就指在第3個元素上。
例子:char * c1 = "hello";
printf("%c/n",*c1);//輸出h
c1++;
printf("%c/n",*c1);//輸出e
5、指標之間的運算
兩個指標之間可以進行減法運算,只有指向同乙個陣列的兩個指標之間進行減法運算才有意義,而指向不同陣列的兩個指標之間進行減法運算則沒有意義。為什麼呢?
指標其實就是記憶體中的位址,兩個指標的減法運算計算的就是兩個記憶體位址之間的元素的個數,比如整數指標p1指向記憶體位址2008h,整數指標p2記憶體位址2000h,而整數佔4個位元組,所以p1-p2的結果就是(2008h-2000h)/4=2,也就是 p1和p2 之間相差 2 個元素。很顯然兩個指標進行加法運算或者兩個指向不同變數的指標進行減法運算都是沒有意義的。
例子:int a1[5]=;
int* p1 = a1;//p1是指向第0個元素的位址
int* p2 = &a1[3];//p2指向的是第3個元素的位址
p1++;//p1指向了第1個元素
printf("%d",p2-p1);//輸出2
6、指標之間的大小比較
指向同乙個陣列的兩個指標之間進行大小的比較是有意義的。比較結果為位址高低的比較:
例子:int a1[5]=;
int* p1 = a1;
int* p2 = &a1[3];
p1++;
printf("%d/n",p2
7、陣列做為引數傳遞給函式
可以將陣列做為傳遞給函式,比如下面的**就是將傳入輸入的每個元素乘以2:
void makedoule(int arr,int len)
,,}
(1)c語言允許把乙個二維陣列分解為多個一維陣列來處理。因此陣列 a 可分解為三個一維陣列,即 a[0],a[1],a[2]。每乙個一維陣列又含有四個元素。例如 a[0]陣列,含有 a[0][0],a[0][1],a[0][2],a[0][3]四個元素。
(2)從二維陣列的角度來看,a 是二維陣列名,a 代表整個二維陣列的首位址,也是二維陣列 0 行的首位址。
特別注意a+1表示第1行的首位址,而不是第0行第第1列的位址,這是初學者最容易犯錯的地方。
同樣a[1]也是第1行一維陣列的陣列名和首位址。
所以a+1、*(a+1)、[1]是等價的。
(4)在二維陣列中不能把&a[i]理解為元素 a[i]的位址,因為a[i]不是乙個陣列元素,a[i]是一種位址計算方法,它本身就表示陣列 a 第 i 行首位址。所以&a[i]和 a[i]是等價的。這一點也是初學者最容易犯錯的地方。
(5)從上邊的分析我們得知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)。
理解了下面的演算法也就理解了多維陣列的指標問題:
int main(int argc, char *argv)
,,};
printf("%d/n",*(*(a+1)+2));
printf("%d/n",*(a[1]+2));
}程式輸出如下:
66兩個表示式都輸出a[1][2]的值。*(a+1)則表示二維陣列a的第1行,也就是等價於a[1]。a[1]、*(a+1)都表示陣列的第1行。所以*(a[1]+2))和*(*(a+1)+2)都表示陣列的第1行的第2個元素的值。
有的同學會問了,既然「*(a+1)」和「a+1」是等價的,為什麼「printf("%d/n",*((a+1)+2)))」輸出結果是錯誤的呢?
編譯器在編譯「*((a+1)+2)))」的時候會把「(a+1)+2」優化成「a+3」,因此「*((a+1)+2)))」就變成了「*(a+3)」,也就是a陣列第3個一維陣列的首位址,顯然這個只是乙個位址,並不是我們想像中的a[1][2]的值,所以輸出了乙個非常大的數。為了避免編譯器的這種誤解,建議大家表示「二維陣列a的第1行」的時候用a[1]或者*(a+1),而盡量不要用(a+1)因為很容易出錯。
9、函式指標
在c語言中,乙個函式總是占用一段連續的記憶體區,而函式名就是該函式所佔記憶體區的首位址。我們可以把函式的這個首位址(或稱入口位址)賦予乙個指標變數,使該指標變數指向該函式。然後通過指標變數就可以找到並呼叫這個函式。我們把這種指向函式的指標變數稱為「函式指標變數」。
函式指標變數定義的一般形式為:
函式的返回值的型別 (*指標變數名)(引數列表);
其中「引數列表」可以省略,不過建議明確標明「引數列表」。
例子:void printit(int i)
int main(int argc, char *argv)
;void (*myaction)(int);
myaction = printit;
for(i=0;i);}}
上面的程式遍歷陣列arr的所有元素,並且列印每個元素。
有的同學會說,這樣做有什麼意義嗎?把「myaction(arr)」直接換成「printit(arr)」不就得了嗎?
這麼替換在這裡是非常合理,也是非常正確的,但是有一天我發現很多地方都要遍歷陣列做不同的事情,為了避免每次都寫for迴圈,我將遍歷陣列的功能抽取到乙個單獨的公共函式中完成
void eachitem(int* parray,int len,void (*action)(int))
; 這兩部分請同學們參考教材。
11、結構指標
對結構的訪問一般形式為:
結構變數.成員名
(*結構指標變數).成員名
或為:
結構指標變數->成員名
應該注意(*pstu)兩側的括號不可少,因為成員符「.」的優先順序高於「*」。
12、結構指標變數作函式引數
允許用結構變數作函式引數進行整體傳送。但是這種傳送要將全部成員逐個傳送,特別是成員為陣列時將會使傳送的時間和空間開銷很大,嚴重地降低了程式的效率。因此最好的辦法就是使用指標,即用指標變數作函式引數進行傳送。
13、動態儲存分配
注:「c語言中不允許動態陣列」是c89標準中的規定,所以tc、vc6等c89等老的編譯器會有這個問題,新的c99中已經不存在這個問題。
c語言中不允許動態陣列型別。例如下面的**是錯誤的:
int n;
scanf("%d",&n);
int a[n];
但是在實際的程式設計中,往往會發生這種情況,即所需的記憶體空間取決於實際輸入的資料。對於這種問題,用陣列的辦法很難解決。為了解決上述問題,c語言提供了一些記憶體管理函式,這些記憶體管理函式可以按需要動態地分配記憶體空間,也可把不再使用的空間**。
(1)分配記憶體空間函式 malloc
呼叫形式:
(型別說明符*)malloc(size)
功能:在記憶體的動態儲存區中分配一塊長度為"size"位元組的連續區域。函式的返回值為該區域的首位址。
(2)釋放記憶體空間函式 free
呼叫形式:
free(void*ptr);
C 指標解惑
之前在使用指標的時候,常常對指標的型別感到困惑,既然所有的指標都只佔4個位元組,那麼他所對應的指標型別在指標轉化過程中有什麼作用呢。最近,終於弄懂了他們的關係,相關說明如下 1.前提首先定義了乙個zooanimal類如下 class zooanimal 2.說明定義如下三個指標 zooanimal ...
C語言解惑要點
1 運算子的優先順序 2 型別轉換 2.1 有符號與無符號數 結果輸出為 2 2 1 2147483647 1 2147483647 2.2 浮點數與整數 3 控制流 這一部分主要需要注意if else之間的巢狀時的配對情況,及迴圈語句的終止條件與狀態。4 轉義字元 除了 n t這一類的轉義字元,還...
快速理解C語言指標
新手在c語言的學習過程中遇到的最頭疼的知識點應該就是指標了,指標在c語言中有非常大的用處。下面我就帶著問題來寫下我對於指標的一些理解。指標是什麼?指標本身是乙個變數,它儲存的是資料在記憶體中的位址而不是資料本身的值。它的定義如下 int a 10,p p a int a 10 int p a 首先我...