C語言資料的儲存超詳細講解中篇練習
前言
本文繼續學習資料在記憶體中儲存的相關知識點。
- 資料儲存
- 整型提升
資料的儲存的知識點練習
通過幾個練習來深入學習資料在記憶體中儲存的知識點,先複習前面學過的整形提升的知識點:C語言操作符超詳細講解下篇
整形提升是按照變數的資料型別的符號來提升的
負數的整形提升,最高位補充符號位,即1,例如
char a=-1;
11111111 截斷後的二補數
11111111111111111111111111111111 整形提升後
正數的整形提升,最高位補充符號位,即0,例如:
char a=1;
00000001 截斷後的二補數
00000000000000000000000000000001 整形提升後
無符號型別的整形提升,最高位直接補充符號位,即0,例如:
unsigned char c = -1;
11111111 截斷後的二補數
00000000000000000000000011111111 整形提升後
練習 1
int main() { char a = -1; signed char b = -1; unsigned char c = -1; printf("a=%d, b=%d, c=%d", a, b, c); return 0; }
查德一看,以為結果是 -1,-1,-1,下面具體分析:
1、char a = -1;
第一步:-1是整數,在記憶體的儲存形式
10000000000000000000000000000001 -1原碼
11111111111111111111111111111110 -1反碼
11111111111111111111111111111111 -1二補數
第二步:賦值給變數a,截斷二補數低位元組的資料
11111111
第三步:以%d的形式列印,先要整形提升,
因為變數a是有符號,且是負數,所以高位補1
11111111111111111111111111111111 二補數
11111111111111111111111111111110 反碼
10000000000000000000000000000001 原碼
第四步:最終列印是的原碼,數值是十進位制 -1
2、signed char b = -1;
過程同有符號變數a的分析過程
3、unsigned char c = -1;
第一步:-1在記憶體的儲存形式
10000000000000000000000000000001 -1原碼
11111111111111111111111111111110 -1反碼
11111111111111111111111111111111 -1二補數
第二步:賦值給變數c,截斷二補數低位元組的資料
11111111
第三步:以%d的形式列印,先要整形提升,
因為變數c是無符號的,最高位1為資料位,
不是符號位,所以高位直接補0
00000000000000000000000011111111 二補數
第四步:因為正數三碼相同
最終列印的是原碼,數值是十進位制255
結果見下圖:
練習 2
int main() { char a = -128; printf("%un", a); return 0; }
查德一看,以為結果是 -128,下面具體分析:
char型別 有符號型別資料範圍 -128-127
char a = -128;
第一步:-128在記憶體的儲存形式
10000000000000000000000010000000 原碼
11111111111111111111111101111111 反碼
11111111111111111111111110000000 二補數
第二步:賦值給char 變數a,發生截斷,取低位元組資料
10000000 - a
第三步:列印%u,首先進行整形提升
因為變數a是有符號,且是負數,所以高位補充符號位,即補1
11111111111111111111111110000000 二補數 負數
第四步:%u,認為是無符號資料,即正數。最高位1為資料位
11111111111111111111111110000000 二補數 正數
第五步:因為正數三碼相同
最終列印的是原碼,數值是十進位制4,294,967,168
結果見下圖:
練習 3
int main() { char a = 128; printf("%un", a); return 0; }
查德一看,以為結果是 128,下面具體分析:
第一步:整形128在記憶體的儲存形式
00000000000000000000000010000000 原碼=反碼=二補數
第二步:賦值給char型別 a,發生截斷,取低位元組資料
10000000 - a
第三步:按照%u列印,先對a進行整型提升,
因為變數a是有符號,且是負數,所以高位補充符號位,即補1
11111111111111111111111110000000 二補數 負數
第四步:%u,認為是無符號資料,即正數。最高位1為資料位
11111111111111111111111110000000 二補數 正數
第五步:因為正數三碼相同
最終列印的是原碼,數值是十進位制4,294,967,168
結果見下圖:
練習 4
int main() { int i = -20; unsigned int j = 10; printf("%dn", i + j); return 0; }
查德一看,以為結果是 -10,下面具體分析:
第一步:整形 -20 在記憶體的儲存形式
10000000000000000000000000010100 原碼
11111111111111111111111111101011 反碼
11111111111111111111111111101100 二補數
第二步:整形 10 在記憶體的儲存形式
00000000000000000000000000001010 原碼
00000000000000000000000000001010 反碼
00000000000000000000000000001010 二補數
第三步:i + j 二補數相加
11111111111111111111111111101100 -20的二補數
00000000000000000000000000001010 10的二補數
11111111111111111111111111110110 相加後的二補數
第四步:最終列印的是原碼,數值是十進位制 -10
11111111111111111111111111110101 反碼
10000000000000000000000000001010 原碼
結果見下圖:
練習 5
int main() { unsigned int i = 0; for ( i = 9 ; i >=0; i--) { printf("%un", i); } return 0; }
查德一看,以為結果是9 到0,共10個數,下面具體分析:
1、i從9到0時,
是正常的輸出9到0
2、i=-1時
第一步:-1是整數,在記憶體的儲存形式
10000000000000000000000000000001 -1原碼
11111111111111111111111111111110 -1反碼
11111111111111111111111111111111 -1二補數
第二步:-1賦值給無符號型別時,認為最高1為資料位
11111111111111111111111111111111 變成的正數的二補數了
數值大於0,又進入迴圈了,所以是死迴圈
結果見下圖:
練習 6
int main() { char a[1000]; int i; for (i = 0; i < 1000; i++) { a[i] = -1 - i; } printf("%dn", strlen(a));//字串長度,字元' '之前的字元個數 printf("%dn", sizeof(a));//字串中字元的個數 return 0; }
查德一看,以為結果是1000、1000,下面具體分析:
char型別 有符號型別資料範圍 -128-127
1、i從0到127時,
是正常的輸出-1 -2 -3 ....-128
2、i=128時
a[128]=-129
第一步:-129是整數,在記憶體的儲存形式
10000000000000000000000010000001 原碼
11111111111111111111111101111110 反碼
11111111111111111111111101111111 二補數
第二步:-129 賦值給char型別a[128]時,發生截斷,取低位元組資料
01111111 - a[128]=127
strlen求得字串長度,是字元 ‘