目录
✂️ 一类型的基本归类
☝️ 1.整型家族
✋ 2.浮点型家族
✋ 3.构造类型 - 自定义类型
✌️ 4.指针类型
✊ 5.空类型
✒️ 二、整型在内存中的存储
✏️ 三、大小端介绍
⚽ 四、百度2015年系统工程师笔试题
⚾️五、练习题
1.⛳
2.⛳⛳
3.⛳⛳⛳
4.⛳⛳⛳⛳
5.⛳⛳⛳⛳⛳
6.⛳⛳⛳⛳⛳⛳
7.⛳⛳⛳⛳⛳⛳⛳
✂️ 一类型的基本归类
☝️ 1.整型家族
char
unsigned char
signed char
short
unsigned short[int]
signed short[int]
int
unsigned int
signed int
long
unsigned long[int]
signed long[int]
⚠️
注意:unsigned char 是无符号的char;signed char 是有符号的char
若以后创建的变量只会存正数,就可以使用 unsigned ,对于用 short 、int 还是 long long 要考虑数值的大小
✋ 2.浮点型家族
float
double
✋ 3.构造类型 - 自定义类型
数组
struct 结构体类型
enum 枚举
union 联合体
✌️ 4.指针类型
int* pi;
char* pc;
float* pf;
void* pv;
✊ 5.空类型
void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型。
✒️ 二、整型在内存中的存储
数据在内存中是以 二进制 的形式存储
对于整数来说:
整数二进制有3中表示形式:原码、反码、补码
正整数:原码、反码、补码相同
负整数:原码、反码、补码是要进行计算的
计算方法:
按照数据的数值直接写出的就是原码
原码的符号位不变,其它位按位取反,得到的就是反码
反码 +1 得到的就是补码
⚠️
注意:整数在内存中存储的是补码。
例子:
#includeint main() { int a = -10; //10000000000000000000000000001010 - 原码 //11111111111111111111111111110101 - 反码 //11111111111111111111111111110110 - 补码 return 0; }
内存中是以十六进制展示的,而我们写出的是二进制,如果把二进制转化成十六进制,再进行比较就可以看出内存中存的是原码、反码、还是补码。
二进制的四个位可以换一个十六进制位,前面28个比特位可以换7个F,0110可以换成6,也就是FFFFFFF6,根据前面的图片可以发现在内存中是倒着存的,这也说明了整数在内存中存的是补码。那么为什么会倒着存?以及为什么存的是补码?将在后面进行解释。。
为什么在内存中存的是补码,而不是原码或反码呢?
原因:在计算机系统中,数值一履用补码表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码和原码相互相互转换,其运算过程是相同的,不需要额外的硬件电路。
例子:
#includeint main() { //1 - 1; //由于CPU只有加法器,所以使用加负1来代替减1 //1 + (-1); //假设使用原码来计算: //1的原码: 00000000000000000000000000000001 //-1的原码:10000000000000000000000000000001 //1 + (-1)的结果是:1000000000000000000000000000010 //转化为十进制是-2,发现并不是我们想要的值 return 0; }
结论:使用原码计算,无法得到我们预期想得到的值。
若使用补码计算:
#includeint main() { //1 - 1; //由于CPU只有加法器,所以使用加负1来代替减1 //1 + (-1); //假设使用原码来计算: //1的补码: 00000000000000000000000000000001 //-1的原码:10000000000000000000000000000001 //-1的反码:11111111111111111111111111111110 //-1的补码:11111111111111111111111111111111 //1的补码: 00000000000000000000000000000001 //-1的补码:11111111111111111111111111111111 //1 + (-1)的结果是:00000000000000000000000000000000 //转化为十进制是0,是我们想要的值 return 0; }
结论:使用补码计算,可以得到我们预期想得到的值,所以要使用补码计算。
✏️ 三、大小端介绍
为什么整数里的正数和负数在内存中是倒着存储的?
解决这个问题要先介绍大端和小端的。那么什么是大端小端?
什么是大端小端:
大端(存储)模式:是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中。
小端(存储)模式:是指数据的高位保存在内存的低地址中,而数据的低位,保存在内存的高地址中。
为什么会有大端和小端:
这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或是32位的处理器,由于寄存器的宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端模式和小端存储模式。
例子:
这里展示用的是16进制,但内存中存的是二进制
正着存倒着存都可以,但是要怎么存进去的,怎么拿出来。
后面两种的存储顺序太复杂了,可以这样存,但是使用起来太复杂了。所以也就保留了前面两种较为简单的顺序。
这四个字节是按照什么样的顺序存在内存中的,我们讨论的是存储在内存中字节的顺序,所以就叫字节序。
字节序分两种:大端字节序,小端字节序。
⚽ 四、百度2015年系统工程师笔试题
请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序
#includeint main() { int a = 1; char* p = (char*)&a; if (*p == 1) { printf("小端n"); } else { printf("大端n"); } return 0; }
函数写法:
#includeint check() { int a = 1; char* p = (char*)&a; if (*p == 1) { return 1; } else { return 0; } } int main() { int ret = check(); if (1 == ret) { printf("小端n"); } else { printf("大端n"); } return 0; }
函数写法的优化版本:
#includeint check() { int a = 1; char* p = (char*)&a; return *p; } int main() { int ret = check(); if (ret == 1) { printf("小端n"); } else { printf("大端n"); } return 0; }
⚾️五、练习题
1.⛳
#include
int main()
{
char a = -1;
//-1的原码:10000000000000000000000000000001
//-1的反码:11111111111111111111111111111110
//-1的补码:11111111111111111111111111111111
signed char b = -1;
//b的补码与a相同
unsigned char c = -1;
//c也是与a相同
printf("a = %d,b = %d,c = %d", a, b, c);
return 0;
}
解析:
内存中存的是补码
char 有一个字节,等于 8 个比特位,-1是有 32 个比特位,将 -1 存到 a 中,a 是 char 类型,a 里面只能存 -1 补码的低 8 位。
11111111
signed char 是一个有符号的 char ,所以和 a 一样,b 里面只能存 11111111
unsigned char 是一个无符号的 char ,但它也是个 char ,c 也只能存 11111111。
要通过 %d 打印一个整型,这里会发生整型提升,因为是有符号位,所以高位要补符号位
11111111111111111111111111111111
这 32 个 1 是补码, %d 打印的是原码,也就是打印 -1 , a 也就等于 -1 , b 与 a 相同。
unsigned char 是无符号的 char ,高位补的是 0
00000000000000000000000011111111
高位是 0 表示它是整数,整数原反补相同
转化为十进制打印也就是 255
补充:
char 到底是 signed char 还是 unsigned char ?
''C语言标准并没有规定,取决于编译器
int 是 signed int
short 是 signed short
结果:
a=-1,b=-1,c=255
2.⛳⛳
#include
int main()
{
char a = -128;
//-128的原码:1000000000000000000000010000000
//-128的反码:1111111111111111111111101111111
//-128的补码:1000000000000000000000010000000
printf("%u", a);
return 0;
}
解析:
a是一个 char 类型,只能存8个比特位。
10000000
%u 打印要发生整型提升,因为是有符号的 char,高位补符号位。
11111111111111111111111110000000
%u 打印一个无符号整型,无符号表示是整数,原反补相同,此时的补码就是原码,转化为十进制后输出结果
如果是以 %d 打印,%d 是打印有符号整数,回通过计算得到原码,最后输出 -128 。
结果:
4294967168
3.⛳⛳⛳
#include
int main()
{
char a = 128;
//128的原码:1000000000000000000000010000000
//因为是正数。原反补相同
printf("%u", a);
return 0;
}
解析:
char 类型只能存8个比特位
10000000
因为是有符号的 char,%u 打印,整型提升,高位补符号位
11111111111111111111111110000000
%u 打印无符号整数,原反补相同,转化为十进制
补充:
char 类型变量的取值范围
结果:
4294967168
4.⛳⛳⛳⛳
#include
int main()
{
int i = -20;
//-20的原码:10000000000000000000000000010100
//-20的反码:11111111111111111111111111101010
//-20的补码:11111111111111111111111111101100
unsigned int j = 10;
printf("%dn", i + j);
return 0;
}
解析:
10是整数,原反补相同
00000000000000000000000000001010
i的补码 + j的补码:
i:11111111111111111111111111101100
j:00000000000000000000000000001010
i + j 的补码:11111111111111111111111111110110
因为以 %d 打印,转化为原码后为
10000000000000000000000000001010
转化为十进制输出结果
结果:
-10
5.⛳⛳⛳⛳⛳
#include
int main()
{
unsigned int i;
for (i = 9; i >= 0; i--)
{
printf("%un", i);
}
return 0;
}
解析:
i是一个无符号整型,不可能为负数,最小是0,%u 打印一个无符号数,判断条件是大于等于0,i的值一直减小到0就不会继续减小了,也就无法跳出循环。
结果:
死循环
6.⛳⛳⛳⛳⛳⛳
#include
int main()
{
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
return 0;
}
解析:
a[i]的值依次为-1 -2 -3......-127 -128 127 126 125......3 2 1 0 -1 -2 ...... -127 -128 127......
因为是char类型,能存的最大负数和最大整数依次是
-128和127
第3题有做详细介绍
结果:
255
7.⛳⛳⛳⛳⛳⛳⛳
#include
unsigned char i = 0;
int main()
{
for (i = 0; i <= 255; i++)
{
printf("hello worldn");
}
return 0;
}
解析:
unsigned char 是无符号的 char,i 的范围只能是0~255,而判断条件是小于等于255,无法跳出。
结果:
死循环



