前面講到“白馬、黑馬”時,我們說一匹白馬和一匹黑馬具有共同的數據類型“馬”,但二者是相對獨立的個體。現在我們以共熟悉的“人”來繼續這個話題,最終引出變量與內存地址的關系。
張三和李四的數據類型都是“人類”。但張三和李四顯然是獨立的量:張三吃了兩塊蛋糕,李四不可能因此就覺和肚子飽了;而李四在下班的路上撿到一個錢包,雖然正好是張三的,兩人似乎通過錢包有了點關系,但誰得誰失仍然不容混淆。
這一切都很好理解。張三和李四之所以是不同的個體,根本原因在于兩人有著不同的肉身。如果是一對連體嬰兒,雖然也是兩個人,但當左邊的嬰兒被蚊子咬一口時,右邊嬰兒是否也會覺得癢,就不好說了。
現在我們困難的是,如何理解兩個不同的變量,也是互相獨立的呢?
答案就在“內存地址”,“內存地址”就是變量的肉身。不同的變量,擁有不同的內存地址。譬如:
char a;
char b;
上面有兩個字符類型的變量a和b,a擁有自已的內存地址,b也擁有自已的內存地址,二者絕不相同。而a、b只不過分別是那兩個內存地址的“名字”,恰如“張三、李四”。
讓我們看圖解:
看,內存就像是開賓館的。不過這有賓館有點怪。首先它每一個“房間”的大小都是一個字節(因此,計算機能單獨處理的最小內存單位為字節)。它的門牌號也不叫房號,而是叫內存地址。
在左圖中,“房客”,變量a住在內存地址為1000002的內存中,而變量b則住在它的隔壁,地址為100003的內存中。另外,如果你足夠細心,你還會發現:內存地址由下往上,從小到大排列。
變量的內存地址是在程序運行時,才由操作系統決定。這就好像我們住賓館。我們預定一個房間,但房間號由賓館根據情況決定,
我們可以改變變量的值,但變量的地址我們無法改變。對照賓館一說,就是我們訂了房間,可以不去住,還可以決定讓誰去住在那個房間里。(當然,現實生活中賓館可能不會允許你這么做)。
在前面圖示的例子中,a、b是字符(char)類型。各占用1個字節。如果是 int類型,那么應該占4個字節。這4個字節必須是連續的。讓我們再來看一個例子:
int a;
int b;
char c;
這回,我們聲明了兩個int類型和一個char類型的變量。同時和上面一樣,我們事實上是假設了這三個變量被依次序分配在相鄰的內存地址上(真實情況下,這和其它因素,如指定的字節對齊方式等有關)。從右圖中可以看到整型變量a占用了1000001~100004這4個字節。
在我們已學習的數據類型中,long double占用10個字節,是占用內存空間最大的一種數據類型。以后我們學習數組,或者用戶自定數據類型,則可能要求占用相當大的,并且同樣必須是連續的空間。因此,如果操作系統僅僅通過簡單的“按需分配”的原則進行內存管理,內存很快就會宣告不足。事實上,操作系統的內存管理相當復雜。幸好,一個普通的程序員并不要求去了解這些內幕。更多的有關內存管理的知識,我們會在下一部課程中學習。但是本章中有關內存的內容卻相當重要。
讓我們來看看我們學了什么:
1、不同的變量,存入在不同的內存地址,所以變量之間相互獨立。
2、變量的數據類型決定了變量占用連續的多少個字節。
3、變量的內存地址在程序運行時得以確定。變量的內存地址不能改變。
除了這些以外,我們現在還要增加幾點:
現在,我們可以明白,為什么需要變量,顯然,這又是一個討好人類的做法。在匯編和機器語言,就是只對內存進行直接操作。但你也看到了,內存地址是一堆長長的數,不好記憶;另外,管理內存復雜易錯,讓程序員直接管理內存顯示不可能。而通過變量,不僅讓內存地址有了直觀易記的名字,而且程序員不用直接對內存操作,何樂而不為呢?事實上,這是所有高級語言賴于實現基礎。
既然變量只不過是內存地址的名稱,所以:
4、對變量的操作,等同于對變量所在地址的內存操作。
第五點是反過來說:
5、對指定內存地址的內存操作,等同對相應變量的操作。
盡管這簡直就是在重復。但這一條卻是我們今后理解C、C++語言相對于其它很多高級語言的,最靈活也最難學的“指針”概念的基石。