下面這些内容存在很高的總結性,可能一句話就需要很大的篇幅和例子進行說明。是以,如果你有疑問可以自己寫代碼測試(個人認為自己寫代碼測試時最好的學習方法),當然也可以在下面評論交流。
1、指針是什麼?指針變量是什麼?
指針是記憶體單元之間的一種指向關系,也是CPU尋址方式的一種展現。CPU在尋址時,如果直接給出存儲單元A的首位址,這種尋址方式叫做直接尋址,而如果給出的不是存儲單元A的首位址,而是先把存儲單元A的首位址存放在另一個存儲單元B中,然後給出B的位址,然後依靠B的位址去通路A的内容,這種尋址方式就叫做間接尋址。此時B儲存A的位址,我們說B指向A,也就是B中儲存的是指向A的指針。當然B中的内容是A的位址。但位址和指針不可以混為一談。
指針變量是一個變量,它儲存的是位址,它展現出的是兩個存儲空間的指向關系。
2、& * 的說明:
首先這是兩個編譯器來識别的運算符。
& 代表變量的位址,首先變量的位址在每一次運作時可能不是固定的,但是它相關于一個基礎位址的偏移量肯定都是一樣的,這個跟程式的載入有關。
* 表示的是取該位址中的值。*p 就表示以p的内容為位址的存儲空間的内容。即 p指向的空間的内容。
3、指針和數組的一緻性
即p = a; a[5] == *(p+5),需要多說一句的是,p+5 表示的首位址按數學方法計算的話是p+5*sizeof(*p)
4、如果a 是數組名,那麼編譯器認為a,&a是同樣的。
5、編譯器關于int a[3][4]的解釋,其實真正的是給定a[1][2](a[i][j]) 的尋址方式,a 是一個int ** 類型的變量,&a[1][2] = a + 1*sizeof(*a) + 2*sizeof(**a) 而sizeof(*a) = 4* sizeof(**a), 同樣的,int (*p)[4];本質上也就是包含兩個資訊,p 是 int ** 類型, p+1 = p + 4*sizeof(int).用下标和*表示數組元素的關系,a[1][2] = *(*(p+1)+2)
6、指針可以進行指派、比較、加減常數運算。
7、不知道為什麼,很多人都喜歡對那幾個字元串處理函數翻來覆去的搞,雖然效率上會有輕微的提升(用了寄存器尋址間接尋址),但是從代碼的可讀性上來說,卻并不算是什麼好事。指針可以提高執行效率,但是代碼的可讀性變差,指針是面向記憶體的根本,也是C語言的靈魂,但是個人感覺還是隻在必要的時候使用。
8、函數指針:指向一個函數的入口位址。定義一個函數指針: 傳回類型 (*p)(參數); eg int (*p) (int); p(1)或(*p)(1)
很多封裝好的語言(java、C#)用這種方式來處理事件,MFC中也大量使用。基本的處理方法就是把一個函數的指針作為參數傳遞到其他的函數中去。當然這種方法對作為參數的函數有嚴格的格式限制。通常如果一個帶有參數的函數名作為參數傳遞時,可以把它的函數名和參數分别作為子函數的參數。eg: void fun(int a){} ==> int fun1(int a, void(*p)()){}; fun1(a,fun);
9、區分下面兩個式子中指針p的含義:
int (*p)[4] 與 int* p[4],這兩個式子中,如果和數組做比較的話,第一個相當于intp[][4],第二個則是int p[4][](當然這樣寫是不符合文法的), p都相當于二級指針,但編譯器對其類型的解釋是:下标的結合性優于*,[]符号可以提前,第一個*p的類型是int[4] 類型,p則是int[4]* 類型,第二個p 是int*[4]類型,如果這樣說仍不太容易了解的話,我們就看編譯器是如何使用他們計算的吧,對于第一個p+1 == p + 4*sizeof(int),*p +1 == *p +sizeof(int), 對于第二個,p+1 == p + sizeof(int *),而*p + 1 == p + sizeof(int) 需要再次說明的是,這些定義的方式是由編譯器所要求,不同的定義,編譯器就有不同的解釋和使用方式,但指針所代表的含義在本質上是一緻的,我們可以用強轉的方式去随意使用他們,當然這樣做也有不好的地方。
10、從上面的了解中,我們再看一個多級指針如何了解
int **p; 它相當于int p[][] ,p + 1 要如何解釋呢? p 是int ** 類型 即 p + sizeof(int*)
對于以上的寫法和概念不應該去死記硬背,而是要了解他們的意義,做到靈活使用就可以了。
int(*p)[4]數組指針,指向一個長度為4的數組的指針,既然是指針,那麼它占用的記憶體空間的長度就隻有4個位元組(32位機)
int*p[4] 指針數組,定義一個數組,數組的元素為指針,占用的記憶體空間數就是length * 4,就是一個常變量。
int** p 指向指針的指針,當然它就是一個指針,占4個位元組。
在給他們配置設定完記憶體空間後,剩下的其實就是編譯器來處理的内容了,規範他們的使用方式。即按下标(數組),或指針加減的方式。在對其指派時,是否具有一緻的尋址算法(即加1表示的意義是否一緻)
使用指針的技巧:保持指針級數相同即可,也就是熟練區分一級指針,二級指針,數組指針等。
11、執行程式時,給定參數的方法。
首先在main函數中,要添加兩個參數(int argc,char* argv[])
執行程式時,給定指令參數,argc會自動儲存指令中字元串的個數,指令本身也算一個,argv[] 數組,則儲存各個參數字元串的位址。注意argv 是指針數組。
雖然從記憶體的角度解釋指針的含義已經簡單了很多,但是由于編譯器對指針的文法限制過于複雜,想要熟練使用,我還需要多加練習。