++++++++++++++++++++++++++++++++++++++++++
《C語言深入理解系列 - 常量與變數》
查看其它博文請關注原創作者。
本文系本站原創,歡迎轉載! 轉載請註明出處:
http://blog.csdn.net/mr_raptor/article/details/7212155
++++++++++++++++++++++++++++++++++++++++++
常量與變數
正所謂靜中有動,動中有靜,常量與變數亦是如此,它們之前相互依賴,相互影響。關於常量與變數,很多朋友可能覺得沒有什麼好介紹的,它實在是太簡單了,單從字面上看就知道什麼意思?我想說的不是關於常量與變數的概念,而是其深入的實質。
其實很多朋友在學到後面指標的時候經常會出現,段錯誤,暈指標(我對那些指標恐懼者的癥狀叫法),野指標等問題,都是因為對常量和變數的理解不夠深入,基礎理解不夠踏實。
常量:其值不會發生改變的量,稱為常量。它們可以和資料類型接合起來分類。比如:整形常量,浮點型常量,字元常量等等,常量是可以不經過定義和初始化,而直接引用的。
常量分類:常量又分為:直接常量和符號常量。
直接常量又叫做:字面常量。如12,0,4.6,’a’,”abcd”
符號常量:如宏定義的:#define PI 3.14
特點:常量的值在其範圍內不會發生改變,也不能再被賦值。其在出現時就被當作一個立即數來使用。也就是說,只能被訪問,被讀,而不能被寫,被賦值。
其實,你一旦聲明了一個常量,那麼常量所在的記憶體空間就被加上了唯讀屬性,它有點類似於const關鍵字。
變數:其值在其範圍內可以改變的量稱為變數。一個變數應該有一個名字,在記憶體中佔據一定的儲存空間。變數在使用前必須要定義。每個變數都有自己的地址。
變數分類:變數依據其定義的類型,分為不同類型,如:整型變數,字元型變數,浮點型變數,指標型變數等等。
特點:變數其值可以發生改變,意味著它可以被覆蓋,被寫入,被賦值。每個變數必須要有一個名字和它所在記憶體空間綁定,xxx所示。
圖xxx 變數記憶體空間
代碼中聲明整型變數a,它的類型已經決定,那麼它的大小也就是4個位元組(32位機上),那麼在記憶體中就有連續的四個位元組與之對應,a變數名就代表了這四個位元組的空間,a變數的地址就是連續四個位元組的開始的地址0x000。就好像是飯店裡每個房間都有一個地址,如201室代表二樓每一個房間,叫201不太雅觀,我們起個名字叫:牡丹廳。那麼,我們人為的將“牡丹廳”這個名字和201房間綁定在了一起。當我們說到牡丹廳,就知道是201房間,同樣當我們說201房間我們也知道是牡丹廳。
同樣的道理,當我們說a變數,就知道是從0x000這個地址開始的4個位元組,當我們說0x000地址就知道這是a變數的空間。那麼既然a是變數也就是說它所代表的空間裡的資料是可以修改的,同樣0x000地址處的資料也是可以修改的。
變數名和變數的值:
變數名是在變數的聲明的時候,該名字就和記憶體中一塊地址綁定在一起了。可以通過變數名直接找到對應的記憶體地區,也可以通過地址找到其記憶體地區。
變數的值是變數所對應的記憶體地區記憶體放的二進位序列。變數的值不會因為變數的類型發生了改變而改變,當變數被轉換為對應類型時,記憶體地區的二進位序列以該類型的形式翻譯出來。這也是強制類型轉換能夠成立的原因。
例如:
int a = 97;<br />char ch1 = ‘a’;<br />char ch2 = (char)a;<br />char *p = (char*)a;
第一行代碼:整型變數a在記憶體中是以97的二進位形式存放的,當使用它時,會被以十進位形式表現出來。
第二行代碼:字元變數ch1的ASCII 碼是97,也是以97的二進位存放的,使用時,會被以字元’a’的形式表現出來。
第三行代碼:將整型變數a強制類型轉換成字元型,a變數裡的值沒有變,變的是它的類型,它裡面的值還是97的二進位,它類型變成了char,97的二進位變成char型,表現出來就是字元’a’。
第四行代碼:聲明一個字元型指標變數p,p是個變數,它裡面的值可變,它的值是整型變數a的值強制類型轉換成了字元指標類型。這個時候p裡的值還是97的二進位,只不過這個97的意義已經代表了一個字元型指標,也就是一個指向字元的地址了。
由此可見:變數在記憶體中存放和它的值沒有關係,而是和它的類型相關的。同樣我們也可以得出:一個二進位序列對於電腦本身而言沒有任何意義,電腦根本不知道這個位元據是幹什麼的,只有具體到它的類型時或出現在合適的場合時,才能代表具體的意義。如果一串位元據出現在地址匯流排上,它代表是一個地址,如果該相同資料出現在資料匯流排上,它代表是一個資料。所以,當我們看到一個資料時,比如:3.1415926,不能把它戴上定向思維的帽子認為它就是PI,而是要看清它的本質,它就是一堆二進位代碼。
我們來看下下面的例子:
1.
char ch = ‘a’;
int a = (int)ch;
printf(“%d %c\n”, a, ch);
ch是什嗎?ch裡裝的是什嗎?a是什嗎?a裡面裝的是什嗎?列印什嗎?
2.
int add = 0x12345678;
int *p = (int*)add;
add是什嗎?add裡裝的是什嗎?p是什嗎?p裡裝的是什嗎?*p又是什嗎?&p又是什嗎?
3.
#define PI 3.14
int a = PI;
printf(“%d\n”, a);
上面的代碼有沒有問題?
4.
#define PI 3.14
printf(“%d\n”, PI);
代碼有沒有問題?
5.
#define PI 3.14
int a = PI;
PI = 3.1415926;
int b = PI;
printf(“%d %d\n”, a, b);
代碼有沒有問題?
6.
char *str = “hello world”;
printf(“%s\n”, str);
*str = “goodbye world”;
printf(“%s\n”, str);
代碼有沒有問題?
答案:
1. 測試對變數類型的理解和類型轉換。ch是字元型變數,ch裡是字元’a’的位元,a是整型變數,a裡面是字元’a’的位元的整型表示方式,以十進位數表示出來97。列印結果為97 和 a。
2. 測試對整型和地址類型轉換。add是一個整數變數,add裡是0x12345678的位元,以十進位表現出來,p是一個整型指標變數名,p裡面是0x12345678的位元,以地址的方式表現出來,代表地址0x12345678。*p是通過*去訪問地址0x12345678這個地址處的資料(如果你試圖去列印它,會出錯,因為這個地址你不一定有許可權去訪問)。&p是取出整型指標變數p的地址,因為p是一個變數,它也有自己的地址,所以可以取出它的地址來(見上面變數的定義)。
3. 宏定義一個常量PI,PI這個符號代表了3.14,在代碼執行前的預先處理階段第二行int a = PI,已經被替換為了int a = 3.14,將3.14賦值給整型,會捨棄掉小數點後面部分結果,僅保留整數部分,列印結果為3。
4. 和上面3一樣,在預先處理階段被替換成了printf(“%d\n”, 3.14),結果為1374389535,這是因為將浮點型的3.14在記憶體中的資料,以整型來表現的。
5. 第三行PI = 3.1415926會出錯,PI是個常量其被替換成了3.14 = 3.1415926,3.14是個字面常量,不能被賦值。錯誤資訊為“向無效左值賦值出錯”(關於常見錯誤資訊,見C語言常見錯誤詳解章節)。
6. 第三行*str = “goodbye world”出錯,第一行中將字串常量“hello world”的首地址給了字元指標變數str,第三行試圖將“goodbye world”的首地址,通過*str的訪問方式覆蓋str指向的字串常量“hello world”。這句話理解起來都比較費勁,因為這裡有兩個錯誤:
“hello world” 是字串常量,那麼這個字串空間裡的內容不能改變。
向一個地址裡寫入字串應該使用strcpy。*str只是代表了str指向的字串中的第一個字元,將字串地址寫入到一個字元裡肯定不行。
關於上面說的,可能現在還不太好理解,請讀者通讀完C語言指標和數組之後再來細品,定會有不同程度的深入理解。
++++++++++++++++++++++++++++++++++++++++++
《C語言深入理解系列 - 常量與變數》
查看其它博文請關注原創作者。
本文系本站原創,歡迎轉載! 轉載請註明出處:
http://blog.csdn.net/mr_raptor/article/details/7212155
++++++++++++++++++++++++++++++++++++++++++