變量的本質是什麼?是一段內存空間,它是程序一定時間內,運行過程中,對其進行讀寫的地方。
變量的名稱代表的是內存空間地址,除去變量迷人的外表:整型,字符型,長整型,指針類型,數組 剩下的就是內存空間。說到空間,就要注意無非大小,方圓幾里?起於何處,止於何方。
那些定義變量的時候叫整型的,或是字符型的是告訴我們世界這麼大,然而變量的心就這麼大,只能容下這麼點心事,多的承受不起。不要超過我的空間大小,我地界之外都是法外之地,到那裡苦海無邊,回頭是岸,家門之內保你無災無妄,是你的心安之處。
現在你明白了所謂變量,加上那些花花綠綠的類型都是都是騙人的,他就是一塊內存裡的給那個變量名為xxx的自留地,變量名稱就是讓你知道他的地址在哪,你需要他指引你到達你想要到達內存空間。
分配給你的自留地是個不毛之地,你要用之前你得清理,初始化它,讓他乾乾淨淨的,要不然他就不是你認為的樣子。記住沒有初始化變量就使用這是個禍害,千刀萬剮的行為,等到有問題的時候就是程序不死,你不能死,他死你更不能死。這是先輩們死在沙灘上血淚教訓,不是危言聳聽,昨天我寫的C語言翻車現場去看看就知道了。
好了言歸正傳,如果你的自留地夠大,你除了種花,種草甚至種樹都可以。瞭解變量空間的本質,你就發現原來C語言世界這麼大,有這麼多神來之筆。
請看下圖演示代碼
1 #include <stdio.h>
2 int main(int argc,char *argv[])
3 {
4 int i = 0;
5 char c = 1;
6 int j = 4417;
7
8 i = c;
9 c = j;
10
11 printf("sizeof(i)=%ld,i=%d,sizeof(c)=%ld,c=%d,c=%c\\n",sizeof(i),i,sizeof(c),c,c);
12 printf("Hex (65)=%0x, Dec (0x1141)=%d\\n",65,0x1141);
13 return 0 ;
14 }
程序會輸出什麼呢?說說你的答案?編譯不通過,報類型錯誤?很遺憾沒有!內存溢出報segment fault! 這個也沒有!!!
使用如下的編譯命令,一點錯誤也沒有
gcc -Wall -o test test.c
./test
結果輸出如下
這回明白了嗎,C語言才不關心你的變量叫什麼,你是什麼類型,他只認那個叫XXX變量的內存自留地,這地有多大。所以 i = c; 沒有任何問題 ,i,c 的空間大小分別為sizeof(i)=4,而sizeof(c)=1 i 容下 c 一點壓力都沒有,但c = j; 呢為什麼沒有內存溢出呢?答案是編譯器幫你自動轉換了,j的十六進制值是0X1141,被截斷了j的高位字節,只取了第一個字節41所以變成c的數值是65,ASCII碼對應的字符是A。對於C語言來說c這個變量只有種一盤花的空間,是種不下j這個大樹的,結果只能砍掉這棵樹一部分再分給c變量。
從上面可以看到C語言給了開發人員很大的自由,這種自由更接近計算機底層本質上處理過程,因為對於計算機來說這個是個空間,只是你要讀寫多少的數據問題。只要這個空間是你的進程可訪問的地址那麼是不受限制的,你需要自己維護這個空間裡數據的完整、一致性、乾淨,給自己留一片淨土。所以不要執迷於變量的類型,受困於這個類型到底能不能賦值,能不能這樣。自留地是你的,你想種什麼花,什麼草,什麼樹那是你的自由。
明白這個你就知道了你定義了一個緩衝char array[1024](什麼緩衝?沒錯這叫緩衝 ,教材叫字符數組,到你那就成了字符串)這個緩衝能放結構類型,能放長整型,能放字符型,浮點型等等。假如有這個一個需求你需要跟銀行進行代收業務交易。你交易的協議約定如下
首1,2字節是包長度 數值, 第3,4,5節是版本號 字符, 第6,7,8,9,10,11字節是本次會話ID 字符往下是包體,包體內容有字符又有數值,但是又如何寫入數據呢,記住變量本質是空間,這個空間是可放不同類型(切確說是不同大小長度)內容的空間
請看下面完整的演示代碼,就明白如何寫入不同的類型了
1 #include <stdio.h>
2 #include <string.h>
3 int main(int argc,char *argv[])
4 {
5 short pkglen=512 ; /* 包長 */
6 char version[4]={"1.0"}; /* 版本 */
7 char sessionid[6]={"123456"}; /* 會話ID */
8 char buf[1024];
9 char *pBuf = buf;
10
11 /* 封裝數據包 */
12 *((short *)pBuf) = pkglen;
13 pBuf = pBuf +2;
14 sprintf(pBuf,version);
15 pBuf = pBuf + strlen(version);
16 sprintf(pBuf,sessionid);
17 pBuf = pBuf +strlen(pBuf);
18
19 /* 解析包 */
20 pBuf = buf;
21 short len = *((short *)pBuf);
22 char v[4];
23 strncpy(v,pBuf + 2,3);
24 v[3]='\\0';
25 char s[6];
26 strncpy(s,pBuf + 2 +3,5);
27 s[5]='\\0';
28 printf("pkglen=%d,version=%s,sessionid=%s\\n",len,v,s);
29 return 0 ;
30 }
結果如下
接著來說說變量的類型,類型切確的說是在C語言中對變量進行操作時每次處理的位寬,例如int 在64位,gcc編譯器下屬
4字節的長度,對某個變量的讀寫每次都是相同的位寬,也是指針前進後退的步長。類型的作用就是告訴計算機每次處理的單元大小
看一下如下代碼演示
1 #include <stdio.h>
2 #include <string.h>
3 int main(int argc,char *argv[])
4 {
5 char array[11]="";
6 strncpy(array, "1234567890", 10);
7 char *p = array;
8
9 p++;
10 printf("*p = %c, addr = %ld\\n",*p, p);
11
12 p = p +3;
13 printf("*p = %c, addr = %ld\\n",*p, p);
14
15 int *pi =(int *) array;
16 pi++;
17 printf("*pi = %c, addr = %ld\\n",*pi,pi);
18 }
輸出:
第一次 p++; 運行後p現在的位置是相對於array 地址的下一個字節處,也就是p前進的位寬是sizeof(char),即array[1]的地址,所以打印出來的結果是2
而pi++;pi 類型的位寬是4個字節,那麼執行pi++後相當於往後走了四步sizeof(char)的大小,但只走了一步sizeof(int),可以看到程序的輸出結果最後p和pi的地址是
相等的,也就是說他們現在都是同一個地方
這就是類型的本質,它限定了每次讀寫的位寬,是按固定位寬單元去訪問。如同之前的12 *((short *)pBuf) = pkglen;
pBuf本來是char在轉換成short後寫入pkglen,直接往長度為4的內存裡寫了512,讀者想想如果是一個結構的類型呢?
總之要記住變量的本質是一段內存空間,它的名稱代表內存空間的位置,而它的類型是讀寫的位寬。
閱讀更多 唯C翹遍 的文章