指針是C/C++的精華,而指針和數組又是一對歡喜冤家,很多時候我們並不能很好的區分指針和數組,對於剛畢業的計算機系的本科生很少有人能夠熟練掌握指針以及數組的用法和區別。造成這種原因可能跟現在大學教學以及現在市面上流行的很多C或者C++教程有關,這些教程雖然通俗易懂,但是在很多關鍵性的地方卻避而不談或者根本闡述不清楚,甚至很多時候闡述的是錯誤的觀點。一般最初學習C/C++的時候接觸到的都是這類教程,學習效果可想而知。對於初學者選擇好的教程真的很關鍵,因為先入為主,一旦你接受了錯誤的觀點或者思想即使後來知道了也一時很難糾正過來(我是深有體會),在此我推薦三本很適合於初學者的教程:
《The C Programming Language》Brian W. Kernighan和Dennis M. Ritchie的經典著作(K&R聖經)
《C ++ Primer》Stanley B. Lippman, Josée Lajoie, Barbara E. Moo C++經典權威著作
《Pointers on C》Kenneth A.Reek
很多時候,會有人說“指著和數組是相同的”,這是一種非常危險的說法,並不完全正確。在一定的上下文環境中,指針和數組是等同的,並非所有情況下如此。然而人們很多時候卻自然而然忽略了這種情況成立的條件,去假定所有情況下都是如此。下面著重談一下指針和數組的區別。
一.指針和數組的定義
指針是指針,指針變量存儲的是一個地址,用來間接訪問數據,在32位系統下,一個指針變量(包括void指針)始終占4個字節的空間。指針可以指向任何內存空間,但不是任何內存空間都可以通過指針去訪問。
數組是數組,定義一個數組之後,編譯器便根據該數組元素的類型和個數在內存開辟一段連續的空間來存放數據,從而直接訪問數據。
下面看一個例子
在file1.c中有如下代碼:
char p[100]="abcdef";
在file2.c中有如下代碼:
#include<stdio.h> extern char *p; int main(void) { printf("%c\n",p[1]); return 0; }
發現能夠編譯通過,但是能正確執行麼?調試發現:出現下圖這個錯誤,無法計算得到p[1]的值。原因稍後作解釋。
從這裡就可以看出,指針和數組並不是等同的,數組的定義並不等同於指針的外部聲明(注意聲明和定義的區別,定義是為一個變量或者對象分配內存空間,而聲明只是描述類型)。
二.指針和數組訪問時的區別
對數組下標的引用:
對指針的引用:
從上面的圖中可以看出,指針和數組根本就是兩個完全不一樣的東西。對於數組,由於編譯器在編譯的時候就已經知道每個符號的地址,因此如果需要一個地址來執行某種操作,可以直接進行操作,並不需要增加指令首先取得具體地址,對於數組就是如此;而對於指針,必須在運行時首先取得它當前的具體值然後才能進行引用。從這點就可以解釋為什麼上面的程序無法正確執行,因為在file1.c中定義的p是一個數組,而在file2.c中卻聲明的是一個指針。因此在file2.c中引用時默認p是一個指針變量,並且會把指針變量中的任何數據當做地址來處理,因此首先取原數組的前4個字節的內容:0x61 0x62 0x63 0x64構成一個地址(暫不考慮大小端的問題)0x61626364,然後按照char型讀取0x61626364這個地址中的內容,但是這個地址可能並不是有效地地址,即使是有效地,也不是我們想要的。大家可以想一下如果在file1.c中將p定義為指針類型,而在file2.c中將p聲明為數組類型,會是什麼情況?
解決上述問題的辦法就是在任何時候保持定義和聲明一致。
測試程序:
file2.c
#include<stdio.h> extern char p[]; extern void print(); int main(void) { printf("%x\n",p[0]); printf("%x\n",p[1]); printf("%08x\n",p); //注意此時p的值是存儲原指針p(file2.c中的p)的內存單元的首地址 print(); return 0; }
file1.c
#include<stdio.h> char *p="abcdef"; void print() { printf("%08x\n",p); printf("%08x\n",&p); }
三.一些應該注意的地方
1.sizeof計算所占空間時的區別。
對於數組,sizeof計算的是整個數組所占的空間,而在32位系統下,sizeof 指針的值始終為4.
2.數組名作為左值時不能被修改,而指針作為左值時可以被賦值。
3.指針可以進行自增(自減)運算(void指針除外,因為void指針無法知道步長),但是數組不能進行自增或者自減運算。
4.理解char *p="abcde"和char str[]="abcde"的區別。
作者:海子