第一:數據類型分類
1.1 基本內置類型
類型 |
別名 |
所佔字節 |
解釋 |
char |
signed char |
1 |
字符數據 |
short |
signed short [int] |
2 |
短整型 |
int |
signed [int] |
4 |
整型 |
long |
signed long [int] |
4 |
長整型 |
long long |
signed long long [int] |
8 |
長長整型 |
float |
- |
4 |
單精度浮點型 |
double |
- |
8 |
雙精度浮點型 |
long double |
- |
8 |
長雙精度浮點型 |
#include <stdio.h>
int main()
{
printf("char %d\n", sizeof(char));
printf("short %d\n", sizeof(short));
printf("int %d\n", sizeof(int));
printf("long %d\n", sizeof(long));
printf("long long %d\n", sizeof(long long));
printf("float %d\n", sizeof(float));
printf("double %d\n", sizeof(double));
printf("long double %d\n", sizeof(long double));
return 0;
}
1.2 取值範圍
類型 |
最小值 |
最大值 |
最小值 |
最大值 |
char |
-2^7 |
2^7-1 |
SCHAR_MIN:-128 |
SCHAR_MAX:127 |
unsigned char |
0 |
2^8-1 |
0 |
UCHAR_MAX:0xff/255 |
short |
-2^15 |
2^15-1 |
SHRT_MIN:-32768 |
32767 |
unsigned short |
0 |
2^16-1 |
0 |
USHRT_MAX:0xffff/65535 |
int |
-2^31 |
2^31-1 |
INT_MIN:-2147483648 |
INT_MAX:2147483647 |
unsigned int |
0 |
2^32-1 |
0 |
UINT_MAX:0xffffffff/4294967295 |
long |
-2^31 |
2^31-1 |
LONG_MIN:-2147483648L |
LONG_MAX:2147483647L |
unsigned long |
0 |
2^32-1 |
0 |
ULONG_MAX:0xffffffffUL/4294967295L |
long long |
-2^63 |
2^63-1 |
LLONG_MIN:-9223372036854775807i64 - 1 |
LLONG_MAX:9223372036854775807i64 |
unsigned long long |
0 |
2^64-1 |
0 |
ULLONG_MAX:0xffffffffffffffffui64 |
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("char min and max = %d\t\t%d\n", SCHAR_MIN, SCHAR_MAX);
printf("unsigned char min and max = %d\t\t%d\n", 0, UCHAR_MAX);
printf("short min and max = %d\t\t%d\n", SHRT_MIN, SHRT_MAX);
printf("unsigned short min and max = %d\t\t%d\n", 0, USHRT_MAX);
printf("int min and max = %d\t\t%d\n", INT_MIN, INT_MAX);
printf("unsigned int min and max = %d\t\t%#x\n", 0, UINT_MAX);
printf("long min and max = %ld\t\t%ld\n", LONG_MIN, LONG_MAX);
printf("unsigned long min and max = %d\t\t%#x\n", 0, ULONG_MAX);
printf("long long min and max = %lld\t\t%lld\n", LLONG_MAX, LLONG_MAX);
printf("unsigned long long min and max = %d\t\t%llu\n", 0, ULLONG_MAX);
return 0;
}
1.3 構造數據
類型 |
關鍵字 |
數組 |
[] |
結構體 |
struct |
聯合體 |
union |
枚舉 |
enum |
1.4 指針和空類型
指針類型是指在類型後面加上一顆*,表示,好比:int* p;表示p是一個整型指針,指向的內存空間爲int。
空指針:void *,好比內存函數:malloc calloc等函數的返回值都爲void*類型,須要強制將其轉化爲指定類型的指針,如:int arr = (int*)malloc(10 * sizeof(10)),即申請了10個int的內存空間。
第二:整型的存儲方式
2.1 存儲方式:
整型數據在內存中是以補碼的方式進行存儲的。
整型:算法
- 有符號位的整型
1.1. 正數:原碼=反碼=補碼
1.2. 負數:反碼=原碼的除符號位以外,其他位取反,補碼 = 反碼+1
- 無符號位整型:原碼=反碼=補碼
2.2 大小端存儲方式
是指字節在內存中存放的順序。
分爲大端存儲(大端字節存儲)和小端存儲(小端字節存儲)
Column 1 |
內存低地址 |
內存高地址 |
小端 |
數據補碼的低位 |
數據補碼的高位 |
大端 |
數據補碼的高位 |
數據補碼的低位 |
判斷系統是以哪一種方式存放數據的。
以下面例子:
數組
// 小端:返回1,大端:返回0
int check_sys()
{
int a = 1;
char* p = (char*)&a;
if (1 == *p)
{
return 1;
}
else
{
return 0;
}
}
// 小端:返回1,大端:返回0
int check_sys_v1()
{
int a = 1;
char* p = (char*)&a;
return *p; // 由於*p == 1,返回1,*p == 0,返回0,因此直接返回*p
}
// 小端:返回1,大端:返回0
int check_sys_v2()
{
int a = 1;
return *(char*)&a; // 由於*p == 1,返回1,*p == 0,返回0,因此直接返回*p
}
int main()
{
int a = 1024;
int ret = check_sys_v2(a);
if (0 == ret)
{
printf("大端字節模式\n");
}
else
{
printf("小端字節模式\n");
}
return 0;
}
2.2.1 例1:
int main()
{
char a = -1; // 由於a是char類型,只佔1個字節,且是小端字節存儲模式,因此將-1的補碼的低8位所佔的字節上的值截取給char a:11111111
signed char b = -1; // signed char b 等價於char a
unsigned char c = -1; // c存的補碼也是11111111,可是爲無符號的整型,則原碼=反碼=補碼,故原碼爲11111111,即255
// 11111111111111111111111111111111 - -1的補碼
// 由於a是char類型,只佔1個字節,且是小端字節存儲模式,因此將存放在低地址中的a的低數據位中的8個比特位截取給a
// 故 a = 11111111 - 補碼
// b是signed char 能夠簡寫爲char b,故與a數據類型相同
// 故 b = 11111111 - 補碼
// 因爲c也是char類型
// 故 c = 11111111 - 補碼
// 由於打印時,是以整型進行打印的,因此須要作提高(按照原符號位進行提高)
// 因爲a是有符號的,且符號位1,則補1,即爲:11111111111111111111111111111111,
// 前24個1爲補的1,則其原碼爲1000...0001,爲-1
// b和a都爲有符號的char,故他們相同
// c是無符號的char,則補0進行提高,即爲00000000000000000000000011111111,其原碼=反碼=補碼,故爲255
printf("a = %d,b = %d,c = %d\n", a, b, c);
return 0;
}
2.2.2 例2:
int main()
{
char a = -128;
// 10000000 00000000 00000000 10000000 - 原碼
// 11111111 11111111 11111111 01111111 - 反碼
// 11111111 11111111 11111111 10000000 - 補碼
// a 爲char佔一個字節:因此截取低地址所存取的值(數據的低位):10000000
// char a:10000000
// %u爲無符號的整型,因此要作提高,因爲char a爲有符號,因此提高位補1:
// 11111111 11111111 11111111 10000000 (提高後),提高後爲無符號,因此其原碼=反碼=補碼其對應的十進制爲;4294967168
printf("%u\n", a);
return 0;
}
2.2.3 例3:
int main()
{
char a = 128;
// 00000000 00000000 00000000 10000000 - 原碼=反碼=補碼
// a 爲char佔一個字節:因此截取低地址所存取的值(數據的低位):10000000
// char a:10000000
// %u爲無符號的整型,因此要作提高,因爲char a爲有符號,因此提高位補1:
// 11111111 11111111 11111111 10000000 (提高後),提高後爲無符號,因此其原碼=反碼=補碼其對應的十進制爲;4294967168
printf("%u\n", a);
return 0;
}
2.2.4 例4:
int main()
{
//9 8 7 6 5 4 3 2 1 0 2^32-1 ...0 2 ^ 32 - 1 ...0往復進行死循環
// 由於當i==0時打印後,執行i--;即i = 0-1 = 0 + (-1) = 32個1
// i 爲無符號整型,因此原碼和補碼相同,即i爲2^32-1
unsigned int i;
for (i = 9; i >= 0; i--)
{
printf("%u\n", i);
}
}
2.2.5 例5:
int main()
{
char a[1000];
int i;
for (i = 0; i <= 1000; i++)
{
a[i] = -1 - i; // -1 -2 .. -128 127 126 ... 1 0 -1 ....
}
printf("%d\n", strlen(a)); // 遇到0中止
return 0;
}
unsigned char i = 0;
int main()
{
for (i = 0; i <= 255; i++)
{
printf("hello, world %d\n", i);0 .. 255 0 .. 255 ...死循環
}
return 0;
}
第三:浮點數在內存的存數形式
3.1 國際標準:
根據國際標準IEEE(電氣和電子工程協會)754規定,能夠將任何一個浮點數(二進制)表示爲如下的通用形式:
3.1.1 公式:
(-1)^S * M * 2^E
註釋:
1. (-1)^S表示符號位,負數:S = 1;正數:S = 0;
2. M:表明有效位數(科學計數法),1 <= M < 2;
3. 2^E:表明指數位數(E),如2^4,E = 4;
S M E存放順序和大小:
(1)對於32位的浮點數:float(佔4個字節,32個比特位)S M E的存放順序和大小爲:
低地址--->高地址:
S:存放第一位(1位);E:存放2-9位(8位);M:存放10-32位(23位)。
(2)對於64位的浮點數:double(佔8個字節,64個比特位)S M E的存放順序和大小爲:
低地址--->高地址:
S:存放第一位(1位);E:存放2-12位(11位);M:存放13-64位(52位)。
3.2 浮點數轉爲二進制的算算法步驟:
(1)整數部分(除2):如:13:
13 / 2 = 6 ... 1
6 / 2 = 3 ... 0
3 / 2 = 1 ... 1
1 / 2 = 0 ... 1 # 當商爲0時,中止運算,將一次獲得的餘數做爲二進制的低位-->高位數據,如:13:1101
(2)小數部分(乘2):如0.875
0.875 * 2 = 1.750 = 1 + 0.75 # 二進制中的左邊第一個1
0.75 * 2 = 1.50 = 1 + 0.5 # 二進制中左邊第二個1
0.5 * 2 = 1.0 = 1 + 0 # 當相乘後小數位0,則中止計算將依次獲得整數位做爲小數二進制的高位-->低位,如:111
如:13.5的二進制爲:00001101.1,即1101.1
將其轉化爲IEEE754標準:(-1) ^ 0 * 1.1011 * 2 ^ 3
即:S = 0;M = 1.1011;E = 3
3.3 S M E 在內存中存放的值
(1)S
若是爲正數:S在內存中存放的是0
若是是負數:S在內存中存放的是1
(2)M
將M的小數部分存放在內存中。
(3)E
E是一個無符號正數;float(8爲:0-255);double(11位:0-2047);
因爲E能夠是負數,當浮點數小於1時,因此存入內存中的E爲真實的E加上一個中間數(double:1023;float:127),即:內存中E = 二進制E + 127 or 1023.
如:float的13.875的二進制:1.1011中的E爲3,則內存中爲3 + 127 = 128 + 2 = 10000010(2^7 + 2 ^ 1)
例如:
13.875在內存中的存放爲:
二進制爲:1101.111
IEEE754:(-1) ^ 0 * 1.101111 * 2 ^ 3, S = 0;M = 1.1011;E = 3
內 存 爲:0 10000010 10111100000000000000000
:0100 0001 0101 1110 0000 0000 0000 0000
十六進制:41 5e 00 00,即:0x415e0000
內存爲 : 00 00 5e 41(低地址-->高地址)
3.4 去讀數據
(1)當E(內存中的E)中同時存在1和0
其值-127或者1023獲得的是IEEE754中公式中的E。
內中的M中爲小數(xxxx),將其加上1,變爲1.xxxx
正數:S= 0;負數:S=1
(2)E(內存中的E)爲全0 爲一個無窮小的數字
真是的E爲1-127 or 1 - 1023
M:不在加上正數部的1. 0.xxxx
S:同上
(3)E(內存中的E)爲全1,若是有效數字全爲0,則表示無窮大數字。
3.5 例子解析
int main()
{
// 00000000 00000000 00000000 00000110 - 6的補碼
// 當以float輸出時,上述爲浮點數的補碼,將其進行讀取爲:S = 0;E = 1 - 126;M = 0.11 爲一個無窮小的數
int a = 6;
float* p = (float*)&a;
printf("a = %d\n", a); // 6
printf("*p = %f\n", *p); // 0.0000000
// 6.0的二進制:110.0 -->IEEE754: (-1)^0 * 1.10 * 2 ^ 2
// S = 0;M = 1.10;E = 2;2 + 127 = 10000001;
// 內存:01000000 11000000 00000000 00000000
// 因此當以整型進行輸出時:爲01000000 11000000 00000000 00000000,爲正數,即爲原碼:
*p = 6.0;
printf("a = %d\n", a); // 01000000110000000000000000000000,十進制:1,086,324,736
printf("*p = %f\n", *p); // 6.0
return 0;
}