當聲明數時,編譯器在連續的內存空間分配基本地址和足夠的儲存空間,以容納數組的全部元素。基本地址是數組第一個元素(索引爲0)的存儲位置。編譯器還把數組名定義爲指向第一個元素的常量指針。數組
元素的地址是經過索引和數據類型的比例因子來計算的;例如: x[3]的地址 = 基本地址 + (3 x 整型數據的比例因子)函數
如何表示元素a[i][j]的(其中:int *p; p = a;);prototype
0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
1 | |||||
2 | |||||
3 | |||||
4 |
數組 a 的基本地址爲 &a[0][0],從這個地址開始,編譯器按行爲全部的元素分配連續的存儲空間。例如:指針
int a[3][4] ={ {15,27,11,35}, {22,19,31,17}, {31,23,14,36} }
數組a的存儲以下:code
|15 |27| 11| 35 |22 |19 |31 |17 |31 |23 |14 |36 | |--索引
若是把 p 聲明爲整型指針,而且初始地址爲a[0][0](),那麼:內存
a[i][j] = *(p+4*i+j);
C語言支持另外一種建立字符串的方法,即便用char類型的指針變量。例如:字符串
char *str = "good";
上述聲明語句建立了一個文本字符串,而後將其地址保存在指針變量str中;這樣指針 str 就指向字符串 「good」 的第一個字符,以下所示:編譯器
|g(str) | o | o | d | \0 | |--it
由此,能夠用指針訪問整個字符串:
printf("%s",str); put(str);
固然,也能夠用指針來訪問字符串中的單個字符。
指針的一項重要的應用就是處理字符串表,特別是處理行的長度可變的「凹凸不平的數組」時;例如:
char *name[3] = { "New Zealand", "Australia", "India" };
上面的聲明語句只分配了28個字符,這足以保存全部的字符,具體以下:
|N| e |w | |Z |e |a |l |a| n| d| \0| |-- |A| u| s| t| r| a| l| i| a| \0| |I| n| d| i| a| \0| 下面的語句能夠用來顯示着三個名稱:
for(i = 0; i <= 2; i++) printf("%s\n",name[i]);
要訪問第 i 個名稱的第 j 個字符,能夠這樣編寫語句:
char c = *(name[i]+j);
使用指針傳遞變量地址的函數調用過程稱爲引用調用(咱們已經說過,傳遞變量實際值的過程稱爲 「按值調用」)。引用調用提供了一種機制,讓被調用的函數能夠修改調用函數中存儲的值。 請注意如下代碼:
//例一 void exchange(int *a, int *b) { int t; t=*a; *a=*b; *b=t; } void main() { int x, y; x = 100; y = 200; printf("%d ,%d\\n",x,y); exchange(&x,&y); printf("%d ,%d\\n",x,y); }
//例二 void exchange(int *a, int *b) { int *t; t=a; a=b; b=t; printf("%d ,%d\n", *a, *b); } void main() { int x, y; x = 100; y = 200; printf("%d ,%d\n", x, y); exchange(&x,&y); printf("%d ,%d\n", x, y); }
代碼例二並不會使x,y的值發生互換,由於當函數指針a,b得到x,y的地址後,做爲值進行儲存,交換a,b的值並無改變其值(x,y的地址)指向的x,y的值。
指針是C語言的一種數據類型,所以也可使用函數返回一個指向調用函數的指針。請看下面的代碼:
int *larger(int* , int*);/*prototype*/ main() { int a = 10; int b = 20; int *p; p = larger(&a, &b);/*Function call*/ printf("%d",p); } int *larger(int *x, int *y) { if(*x > *y) return(x);/*address of a*/ else return(y);/*address of b*/ }
注意:返回的地址必須是調用函數中變量的地址。若是返回的是指向被調用函數中局部變量的地址;將產生錯誤。
與變量同樣,函數也屬於某種數據類型,在內存中也須要有儲存地址。所以能夠聲明一個指向函數的指針。如同指向字符數組的指針,能夠接收任意大小的字符數組同樣,指向函數的指針能夠指向任意的函數,如此能夠減小函數的數量,使函數的功能更增強大。指向函數的指針聲明以下:
type (*fptr)();
該語句告訴編譯器,fptr爲指向函數的的指針,返回type類型的值。用括號把*fptr括起來是必要的。記住,下面的語句:
type *gptr();
表示的是把gptr聲明爲函數,它返回一個指向type類型的指針。
請仔細關注如下代碼:
#include<stdio.h> #include<math.h> #define PI 3.1415926 double table(double (*f)(), double, double, double); double y(double); double cos(double); double table(double (*f)(), double min, double max, double step) { double a, value; for(a = min;a <= max; a+=step){ value = (*f)(a); printf("%5.2f %10.4f\n,a,value"); } } double y(double x) { return (2*x*x-x+1); } void main() { printf("table of y(x) = 2*x*x-x+1\n\n"); table(y, 0.0, 2.0, 0.5); printf("table of cos(x)\n\n"); table(cos, 0.0, PI, 0.5); }
在前面章節中,咱們討論把結構體做爲參數傳遞給函數。咱們還看到這樣的實例,其中函數接收整個結構體的副本,並在運行後把他返回給調用函數。正如咱們前面介紹的那樣,該方法不管是在運行速度仍是在內存使用上都不是高效的。經過以指向結構體的指針做爲傳遞參數,而後使用指針來操縱結構體成員,就能夠克服該缺點。請看如下函數:
print_invent(struct *item) { printf("Name: %s\n", item->name); printf("price:%f\n", item->price); }
該函數能夠用下面的語句來調用:
print_invent(&product);
請關注如下兩點: