TCPL(The C Programming Language)讀書筆記 第五章 指針與數組

1、指針與地址

   指針是一種保存變量地址的變量。

機器的一個字節可以存放一個char類型的數據,兩個相鄰的字節存儲單元可存儲一個short(短整型)類型的數據,而4個相鄰的字節存儲單元可存儲一個long(長整型)類型的數據。指針是能夠存放一個地址一組存儲單元(通常是兩個或4個字節)

一元運算符&可用於取一個對象的地址,它只能應用於內存中的對象,即變量與數組元素。不能作用於表達式、常量或register類型的變量。

一元運算符*是間接尋址或間接引用運算符,當它作用於指針時,將訪問指針所指向的對象。

我們應該注意,指針只能指向某種特定類型的對象,也就是說,每個指針都必須指向某種特定的數據類型。(一個例外情況是指向void類型的指針可以存放指向任何類型的指針,但它不能間接引用其自身。)

例子:將ip指向的對象的值加1,可以寫成

*ip += 1;

++*ip;

(*ip)++;

需要注意的是,第三個語句中的圓括號是必需的,否則,該表達式將對ip進行加1運算,而不是對ip指向的對象進行加1運算,因爲類似與*++這樣的一元運算符遵循從右至左的結合順序。

最後說明一點,由於指針也是變量,所以在程序中可以直接使用,而不必通過間接引用的方法使用。如,若iq是另一個指向整型的指針,那麼 iq = ip;將把ip中的值拷貝到iq中,這樣,指針iq也將指向ip指向的對象。

fromC和指針》:變量的值存儲於計算機的內存中,每個變量都佔據一個特定的位置。每個內存位置都由地址唯一確定並引用,就像一條街道上的房子由它們的門牌號碼標識一樣。指針只是地址的另一個名字罷了。指針變量就是一個其值爲另外一個(一些)內存地址的變量。

另外,ANSI C則聲明如果對一個字符串常量進行修改,其效果是未定義的。它也允許編譯器把一個字符串常量存儲於一個地方,即使它在程序中多次出現。這就使得修改字符串常量變得極爲危險,因爲對一個常量進行修改可能殃及程序中其他字符串常量。因此,許多ANSI編譯器不允許修改字符串常量,或者提供編譯時選項,讓你自行選擇是否允許修改字符串常量。在實踐中,請儘量避免這樣做。如果你需要修改字符串,請把它存儲於數組中。

記得常量就是不能更改的固定值就行了。一個常量存在一個內存空間中,不能試圖去修改它,除非重新分配內存空間。

strcpy(char *,asdsfj)  //right

strcpy(asdsfj,char *)  //wrong

2、指針與函數參數

由於C語言是以傳值的方式將參數傳遞給被調用函數。因此,被調用函數不能直接修改主調函數中變量的值。例如,

void swap(int x,int y)

{  ...   }

則在主函數中,

int a = 3,b = 2;

swap(a,b)

達不到交換目的。因爲,參數傳遞採用傳值方式,因此swap函數不會影響到調用它的例程中的參數ab的值。該函數僅僅交換了ab的副本的值。實際上兩個ab不是一個變量,一個是實參一個是形參,在內存裏是分別分配兩個內存空間的,形參交換了也沒用,等swap函數運行結束,裏邊所有的臨時變量全部銷燬了!

3、 指針與數組

通過數組下標所能完成的任何操作都可以通過指針來實現。

int a[10];

int *pa;

pa = &a[0];(等價語句:pa = a;)

pa指向數組中的某個特定元素,那麼根據指針運算的定義,pa+1將指向下一個元素,pa+i指向pa所指向數組元素之後的第i個元素。因此,若指針pa指向a[0],那麼*(pa+1)引用的是數組元素a[1]的內容,pa+i是數組元素a[i]的地址*(pa+i)引用的是數組元素a[i]的內容。

無論數組a中元素的類型或數組長度時什麼,上面結論都成立。“指針加1”就意味着,pa+1指向pa所指想想的對象的下一個對象。

兩個等價的表達方式:&a[i]a+i的含義是相同的,是a之後的第i個元素的地址;相應的,如果pa是個指針,那麼,在表達式中也可以在它的後面加上下標,即pa[i]*(pa+i)是等價的。簡而言之,一個通過數組和下標實現的表達式可等價地通過指針和偏移量實現

    注意:數組名和指針的不同之處,指針是一個變量,因此,在C語言中,語句pa = a pa++都是合法的,但數組名不是變量,因此,a=paa++是非法語句。

    在函數定義中,形式參數 char s[];char *s;是等價的。也可以將指向子數組起始位置的指針傳遞給函數,這樣,就將數組的一部分傳遞給了函數。例如,a是一個數組,那麼f(&a[2])f(a+2)都是將把起始於a[2]的子數組的地址傳遞給函數f

4、 地址算術運算

指針與整數不能互相轉換,但0是唯一的例外:常量0可以賦值給指針,指針也可以和常量0進行比較。程序中經常用符號常量NULL代替常量0,這樣便於更清晰地說明常量0是指針的一個特殊值。

有效的指針運算包括相同類型指針之間的賦值運算指針同整數之間的加法或減法運算;指向相同數組中元素的兩個指針間的減法或比較運算;將指針賦值爲0指針與0之間的比較運算。

其他所有形式的指針運算都是非法的,例如兩個指針間的加法、乘法、除法、移位或屏蔽運算;指針同floatdouble類型之間的加法運算;不經強制類型轉換而直接將指向一種類型對象的指針賦值給指向另一種類型對象的指針的運算(兩個指針之一是void *類型的情況除外)。

5、 字符指針與函數

無。

6、 指針數組以及指向指針的指針

由於指針本身也是變量,所以它們也可以像其它變量一樣存儲在數組中。

char *p[MAXNUM];

它表示p是一個具有MAXNUM個元素的一維數組,其中數組的每個元素是一個指向字符類型對象的指針。也就是說,p[i]是一個字符指針,而*p[i]是該指針指向的第i個文本行的首字符。

7、 多維數組

C語言中,二維數組實際上是一種特殊的一維數組,它的每個元素也是一個一維數組。數組元素按行存儲,因此,當按存儲順序訪問數組時,最右邊的數組下標(即列)變化的最快。

如果將二維數組作爲參數傳遞給函數,那麼在函數的參數聲明中必須指明數組的列數。數組的行數沒有太大關係,因爲前面已經講過,函數調用時傳遞的是一個指針,它指向由行向量構成的一維數組。

例如:

f(int t[2][13]){ ... }

f(int t[][13]) { ... }

f(int (*t)[13]) { ... } //參數是一個指針,它指向具有13個整型元素的一維數組

8、 指針數組的初始化

在此舉例說明:

static char *name[] = {

Illegal month,January,February,March,

April,May,June,July,August,September,

October,November,December

};

name是一個一維數組,數組的元素爲字符指針。name數組的初始化通過一個字符串列表實現,列表中的每個字符串賦值給數組相應位置的元素。i個字符串的所有字符存儲在存儲器中的某個位置,指向它的指針存儲在name[i]。由於上述聲明中沒有指明name的長度,因此,編譯器編譯時將對初值個數進行統計,並將這一準確數字填入數組的長度。

9、 指針與多維數組

指針與二維數組之間的區別。假如有下面兩個定義:

int a[10][20];

int *b[10];

a是一個真正的二維數組,它分配了200int型長度的存儲空間,並通過常規的矩陣下標計算公式20*row+col計算得到元素a[row][col]的位置。但是對b來說,該定義僅僅分配了10個指針,並且沒有對它們初始化,它們的初始化必須以顯式的方式進行,比如靜態初始化或通過代碼初始化。

指針數組的一個重要優點是,數組的每一行長度可以不同,甚至某些元素可以不指向任何向量。所以指針數組最頻繁的用處是存放具有不同長度的字符串。

10、命令行參數

在支持C語言的環境中,可以在程序開始執行時將命令行參數傳遞給程序。調用主函數main時,它帶有兩個參數。第一個參數(習慣上稱爲argc,用於參數計數)的值表示運行程序時命令行中參數的數目;第二個參數(稱爲argv,用於參數向量)是一個指向字符串數組的指針,其中每個字符串對應一個參數。

  

比如你生成的exe文件是e:/myproject/project1.exe

進入命令行提示符(開始--程序--附件裏面)

然後打命令

e:

cd myproject

project1 字符串1 字符串2

就可以執行了。

本節內容不太能理解!

11、指向函數的指針

C語言中,函數本身不是變量,但可以定義指向函數的指針。這種類型的指針可以被賦值、存放在數組中、傳遞給函數以及作爲函數的返回值等等。

任何類型的指針都可以轉換爲void*類型,並且在將它轉換回原來的類型時不會丟失信息。

int (*comp)(void*,void*)

它表明comp是一個指向函數的指針,該函數具有兩個void*類型的參數,其返回值類型爲int

如果寫成下面的形式:

int *comp(void*,void*)

則表明comp是一個函數,該函數返回一個指向int類型的指針。

12、複雜聲明

關於複雜聲明,需理解:

char **argv

    argv:pointer to char

int (*daytab)[13]

    daytab:pointer to array[13] of int

int *daytab[13]

    daytab:array[13] of pointer to int

void *comp()

    comp:function returning pointer to void

void (*comp)()

    comp:function returning pointer to void

char(*(*x())[])()

x:function returning pointer to array[] of pointer to function returning char

    char(*(*x[3])())[5]

x:array[3] of pointer to function returning pointer to array[5] of char

 

指針使用:

①使用之前重新定義個同類型指針作爲該指針的頭指針,以防使用過程中指針位置變化後找不到頭指針的位置。

② 要使用的指針最好作爲一個不變的量存在,可以定義一個同類型指針指向它,然後在程序中使用。

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