1.1 C语言中的内置类型
首先,C语言中本身存在了这几种数据类型
类型的意义取决了,你所定义一个变量时,需要开辟多少的空间。
1.2 C语言的类型分类
我们知道C语言中有这么多类型了,那么该如何分类呢?
整型家族
可以看到,整型家族的类型,有被unsigned和signed这两个关键字所修饰。
首先,我们所定义的变量默认都是有符号数的,也就是被signed所修饰。
那么unsigned 和 signed的区别是什么呢?
signed
一个int是4个字节,占用4B,也就是32个比特位,最高位为符号位,符号位0为正,1位负,但是符号位不参与计算。
unsigned
对于unsigned所修饰的变量,没有符号位,它是计入运算的
最后,生活中的一些事物,只有正数没有负数,比如身高,体重,所以这时我们使用unsigned来修饰更加贴切.
unsigned int height = 180;
浮点数家族
浮点数家族只有2个,double比float所表达的范围更广,更精准一些
构造类型
构造类型也称为自定义类型,比如数组的在定义时,
int arr[10] 的类型为 int [10]
char arr[5] 的类型为char [5]
类型是不相同的
指针类型
空类型
void类型为空类型,常用于函数的返回值,函数的参数,指针类型
1.3 数值的表示类型
数值有不同的表示形式
此外,整数二进制也有3中表示方式,它们就是原码,反码,补码
- 正的整数,原码、反码、补码相同
- 负的整数,原码、反码、补码是需要计算的
原码
:直接通过正负的形式写出的二进制序列就是原码
反码
:原码的符号位不变,其他位按位取反得到的就是反码
补码
:反码+1就是补码
那么在内存中,存储的是原码是反码还是补码呢?
#include <stdio.h>
int main()
{
int a = 20;
//20
//00000000000000000000000000010100-原码
//0x00 00 00 14
//00000000000000000000000000010100-反码
//00000000000000000000000000010100-补码
//
int b = -10;
//10000000000000000000000000001010--原码
//0x80 00 00 0a
//11111111111111111111111111110101--反码
//0xfffffff5
//11111111111111111111111111110110--补码
//0xfffffff6
//
return 0;
}
结论:整数在内存中存放是补码的二进制序列
疑问:问什么我们算出来的数是0xfffffff6,而在内存监视中是倒着的呢?
1.4 大小端和字节序
大端:把一个数据的低位字节序放在高地址处,高位字节序放在低地址处。
小端:把一个数据的低位字节序放在低地址处,高位字节序放在高地址处。
1.5 练习
练习
:写一段程序,判断当前机器的字节序
思路:我们知道了,机器是按小端存储,可以定义一个
int a = 1 变量,整型占用4个字节,我们可以取它第1个字节,如果是1,那么就说明是小端,否则是大端。
实现:
#include <stdio.h>
int check_fun(int n)
{
return *(char*)(&n);
}
int main()
{
int a = 1;
int r = check_fun(a);
if (r)
{
printf("小端");
}
else {
printf("大端");
}
return 0;
}
练习1:输出这段程序的结果
#include <stdio.h>
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;
}
char a 的计算过程
(1)-1是int整数,先计算-1的原反补码
10000000 00000000 00000000 00000001 -1的原码
11111111 11111111 11111111 11111110 -1的反码
11111111 11111111 11111111 11111111 -1的补码
因为是char,存储一个B
11111111 (补码截断存储到char中)
(2)%d 打印的有符号的整型
11111111 11111111 11111111 11111111 (整型提升,因为是有符号数,补充的是符号位)
10000000 00000000 00000000 00000000
10000000 00000000 00000000 00000001
-1
unsigned char c 的计算过程
(1)先存储到char中
10000000 00000000 00000000 00000001 -1原码
11111111 11111111 11111111 11111111 -1补码
11111111 (截断)
(2) %d 打印的是有符号整型,unsigned char c 进行整型提示,因为是无符号类型,所以补0
00000000 00000000 00000000 11111111 -整型提升,因为是无符号数,补0
255
练习2:这段程序的输出结果
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n",a);
return 0;
}
10000000 00000000 00000000 10000000
11111111 11111111 11111111 01111111
11111111 11111111 11111111 10000000 - 截断
10000000 - a
11111111 11111111 11111111 10000000 - 先看定义的类型,是char,是有符号char的整型提升,补符号位
练习3:下列程序的输出结果
#include <stdio.h>
int main()
{
char a = 128;
printf("%u\n",a);
return 0;
}
00000000000000000000000010000000
10000000 - a
练习4:下列程序的输出结果
#include <stdio.h>
int main()
{
int i = -20;
//10000000000000000000000000010100
//11111111111111111111111111101011
//11111111111111111111111111101100 - -20的补码
//
unsigned int j = 10;
//00000000000000000000000000001010 - 10的补码
printf("%d\n", i + j);
printf("%u\n", i + j);
//11111111111111111111111111101100
//00000000000000000000000000001010
//--------------------------------
//11111111111111111111111111110110 - 因为打印%d,所以认为是有符号数的补码,是负数,要求原码
//10000000000000000000000000001001
//10000000000000000000000000001010 -> -10
return 0;
}
-10
练习5
unsigned int i;
for(i = 9; i >= 0; i--)
{
printf("%u\n",i);
}
输出结果原因:因为是unsigned int,所以不可能为负数,经过计算后,是一个非常大的正数
练习6
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d",strlen(a));
输出结果原因:
a[0] = -1
a[1] = -2
…
a[127] = -128
a[128] = 127
…
a[254] = 0
数组中的元素是不断减一,而char的取值范围是-128~127,所以当-128减1时,是等于127,再减一,直到0,而strlen这个函数是求’\0’之前的元素个数,它的ASCII码值等于0,所以负的数加正的数,共128+127=255个元素
练习7
unsigned char i = 0;
int main()
{
for(i = 0;i<=255;i++)
{
printf("hello world\n");
}
return 0;
}
输出结果是无限循环,因为unsigned char 的取值范围是0-255,当i = 255时,再加1,i=0了,所以就是无限的循环。