基础数据类型
数据类型
C语言必须在使用变量前确定类型并定义
基础类型
C语言基础类型表
C语言类型 | |||||
---|---|---|---|---|---|
整数 | Char | Short | Int | Long | Long long |
浮点数 | Float | Double | Long double | ||
逻辑 | bool | ||||
指针 | |||||
自定义类型 |
表达数的范围: char < short < int < float < double
内存占据大小: 1字节~16字节
内存中的表达式: 二进制数(补码) , 编码
输入输出
类型名称 | 格式化 |
---|---|
int | %d |
long | %ld |
double | %lf |
unsinged | %u |
unsigned long long | %lu |
小于int的类型:char
,short
,int
才用同一种输出格式:%d
大于int的类型:输出格式%ld
sizeof
sizeof是一个运算符,其用处是给出某个类型或变量在内存中占据的字节数
用法: sizeof(类型/变量)
sizeof不会做计算,执行sizeof(int+1.0)
会输出double类型的字节数
整数
类型 | 字节数(1字节=8比特) |
---|---|
char | 1 |
short | 2 |
int | 取决于CPU |
long | 取决于CPU |
long long | 8 |
整数的内部表达
比int类型小的数据表达的是寄存器中的某些位,而比int大的表达的可能是多个寄存器拼凑起来的,但是不管怎么说,计算机内部都是二进制数
补码
从不同角度看是不同的数值
补码的意义就是拿补码和原码可以加出一个溢出的0
负数的补码计算方式0 - a
另一种方式2^n -a
,n是这种类型的位数
-1 + 1 = 0
- 0 –> (1)00000000
- 1 –> 00000001
(补码-1)11111111 + 00000001 = 100000000
所以-1 + 1 = 00000000
0 - 1 = -1
- 0 –> (1)00000000
- 1 –> 00000001
(1)00000000 - 00000001 = 11111111
所以 0 -1 = 补码形式的11111111
整数的范围
对于一个字节(8位),可以表达的是从00000000 ~ 11111111
其中00000000 为 0
11111111 ~ 100000000 为 -1 ~ -128
00000001 ~ 01111111 为 1 ~ 127
1 |
|
由此可见,不同类型的数据的范围是不同的
类型 | 字节数 | 范围 |
---|---|---|
char | 1字节 | -128 ~ 127 |
short | 2字节 | -32768 ~ 32767 |
int | 取决于CPU | -2^32-1 ~ 2^32-1 -1 |
Unsigned
主要作用是为了移位做纯二进制运算
该类型的整数不以补码形式表示负数,只有正整数和0
表达正数时会将数值扩大一倍
如果一个字面量常数想表达自己是Unsigned,可以在后面加上u或U,例如:255U
整数越界
整数是以纯二进制方式进行计算的
11111111 + 1
–> 10000000
= 0
01111111 +1
–> 10000000
= -128
10000000 -1
–>01111111
= 127
1 |
|
选择整数类型
- 整数之所以有这么多种是为了更准确得表达内存,做底层程序的需要
- 没有特殊的需求情况下选择int类型就好
- Unsigned与否只是输出的不同,但在内部计算仍然是一样的
进制
计算机只认识2进制,其他进制的数据都会被转换成2进制
其他进制只是如何把数字表达成字符串,但与内部如何表达数字没有关系
- 以
0
开头的数字字面量是8进制 - 以
0x
开头的数字字面量是16进制 - %o用于将8进制输出10进制,%x/X用于将16进制输出10进制
- 16进制更适合表达2进制数据,因为4位二进制正好是一个16进制位
浮点类型
类型 | 字长 | 范围 | 有效数字 |
---|---|---|---|
float | 32 | ±(1.20×10^-38 ~ 3.40×10^38),0,±inf(无穷大),nan(非数字) | 7 |
double | 64 | ±(2.2×10^-308 ~ 1.79×10^308),0,±inf(无穷大),nan(非数字) | 15 |
输入输出
初始化float类型的变量时,需要在其后面指定f或F后缀来表明是float类型,否则按double来表达
类型 | 输入 | 输出 |
---|---|---|
float | %f | %f,%e/%E(科学计数法) |
double | %lf | %f,%e/%E(科学计数法) |
精度
浮点数的运算没有精度可言
在%和f之间加上.n
可以指定输出小数点后n位,这样的输出结果是做4舍5入(向下取整)的
范围
当0.0作为除数时,其结果就是无限大,而整数类型的0作为除数时无法编译
- printf输出inf 表示超过范围的浮点数:±∞无穷大
- printf输出nan 表示不存在的浮点数
1 |
|
选择浮点类型
同整数类型一样,选择相对来说范围较大的一个即可
在没有特殊需求的情况下,选择使用double就好
字符
之前说过Char是一种整数,但它也是一种特殊的类型:字符
- 用单引号表示的字符字面量:
'x'
,1
''
也是一个字符- printf和scanf里用%c来输入和输出字符类型
字符的编码才用ASCII码
当输入的是整数类型,输出格式是字符格式时,会对应ASCII码
同一个输入内容,当输出格式不同时会各自表述
1 |
|
混合输入
当scanf里以空格分割时,输入也需要带上空格
而没有使用空格的情况下,整数后的任意输入都会被记录在后面的char类型里,包括换行符号
字符计算
字符也可以做整数的运算,当然输出的也得是字符类型
一个字符加一个数字得到
ASCII
表中那个数之后的字符两个字符相减,则得到它们在
ASCII
表中的距离例如
1 | char c = 'A'; |
大小写转换
- 字母在
ASCII
表中的排列是顺序的 - 大写字母和小写字母是分开排列的,并不能在一起
- a~A 可以得到两段之间的距离,于是:
a + 'a' - 'A'
可以把一个大写字母变成小写字母a + 'A'- 'a'
则可以把一个小写字母变成大写字母
类型转换
自动类型转换
当运算符两边出现不一致的类型时,会自动转换成能表达范围更大的类型
char –> short –> int –> long –> long long
int –> float –> double
对于printf来说,任何小于int的类型都会被转换成int,float会被转换成double
但对于scanf来说,得明确类型大小,要输入short时,需要%hd
强制类型转换
当需要把一个量强制转换成另一个较小范围的类型
格式(类型)值
(int)2.0
但是小的变量类型不能表达大的值;因为整数越界,所以
(short)32768 --> -32768
强制类型转换只是从变量计算出一个新的类型的值,不会改变变量,无论是值还是类型都不会被改变
优先级
强制类型转换的优先级高于四则运算
逻辑类型
bool
bool类型作为非原生类型,需要在头文件加上#include <stdbool.sh>
才能使用bool
,true
,false
真正意义上并没有所谓bool类型,它们仍然是整数
所以输出的时候也只能是输出整数类型的bool
1 |
|
逻辑运算
逻辑运算是对逻辑量进行的运算,结果只有0或1
而逻辑量是关系运算或逻辑运算的结果
- 不要将赋值,包括复合赋值组合进表达式!
- 逻辑运算是自左向右进行的,如果左边的结果已经能够决定结果,就不会再做右边的计算了
运算符 | 描述 | 示例 | 结果 |
---|---|---|---|
! | 逻辑非 | !x | 如果x是true则结果为false,反之如果x是false则结果为true |
&& | 逻辑与 | x && y | 如果x和y都是true,结果就是true,否则任一为false其结果就是false |
|| | 逻辑或 | x || y | 如果x和y有一个是true,结果就是true,只有两者都是false时,结果才是false |
e.g
x ∈(2,5)
–> x > 2 && x < 5
x ∈[3,5]
–> x >= 3 && x <= 5
判断大写字母
x = 'A' && x <= 'Z'
判断小写字母
x = 'a' && x <= 'z'
优先级
这三个逻辑运算的优先级是! > && > ||
而且||
和&&
是自左向右运算的
!error && finish || done
当error不为0并且finish 或 done有一个为true,那么结果就为true,否则为false
1 |
|
优先级 | 运算符 | 结合性 |
---|---|---|
1 | () | 从左到右 |
2 | ! + - ++ – | 从右到左(单目的+和-) |
3 | * / % | 从左到右 |
4 | + - | 从左到右 |
5 | < <= > >= | 从左到右 |
6 | == != | 从左到右 |
7 | && | 从左到右 |
8 | || | 从左到右 |
9 | = += -= *= /= %= | 从右到左 |
其他
条件运算符(三目运算符)
它的作用和if是一样的,这是编程语言早期遗留下的东西,和if一样可以嵌套使用,不过写法和易懂性很差
条件运算符的优先级高于赋值运算符,但是低于其他的运算符
条件运算符是自右向左结合的
格式:
x = y * 5 > 10 ? 3 : 2
其中?前面是条件,?后面是条件满足时的值,:后面是条件不满足时的值,如果把它写成if语句就是:
1 | if ( y * 5 > 10 ){ |
逃逸字符(转义字符)
其作用是为了表达无法输出的控制字符或特殊字符,使用反斜杠\
开头,后面跟上需要逃逸(转义)的字符,这两个字符合起来,组成了一个可以正常输出的字符
字符 | 别名 | 作用 |
---|---|---|
\a | 响铃符 | 触发蜂鸣器 |
\b | 回车 | 回退一格 |
\t | table | 到下一个表格位 |
\n | 回车换行 | 换行 |
\“ | 双引号 | 将”变成普通字符 |
\‘ | 单引号 | 将’变成普通字符 |
\\ | 反斜杠 | 输出反斜杠本身 |
\b
回退的含义并不是删除前一位字符,而是将\b后一位字符补进前一位
1 |
|
\t
table是每行固定的四个空格,只要输出的字符占据table以内的字符都是按照对齐的方式排列的
- 一个\t可以使得输出从下一个制表位开始
- 用\t才能使得上下两行对齐
总结
类型字节数与范围
类型 | 存储大小 | 值范围 |
---|---|---|
char | 1 字节 | -128 到 127 或 0 到 255 |
unsigned char | 1 字节 | 0 到 255 |
signed char | 1 字节 | -128 到 127 |
int | 2 或 4 字节 | -32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647 |
unsigned int | 2 或 4 字节 | 0 到 65,535 或 0 到 4,294,967,295 |
short | 2 字节 | -32,768 到 32,767 |
unsigned short | 2 字节 | 0 到 65,535 |
long | 4 字节 | -2,147,483,648 到 2,147,483,647 |
unsigned long | 4 字节 | 0 到 4,294,967,295 |
float | 4 或8 字节 | 1.2E-38 到 3.4E+38 |
double | 8 字节 | 2.3E-308 到 1.7E+308 |
long int | 4 或 8字节 | |
long long | 8字节 | |
long double | 8 或 12 或 16字节 | 3.4E-4932 到 1.1E+4932 |
运算符优先级
类别 | 运算符 | 结合性 |
---|---|---|
后缀 | () [] -> . | 从左到右 |
一元 | + - ! ~ ++ - - (类型) * & sizeof | 从右到左 |
乘除 | * / % | 从左到右 |
加减 | + - | 从左到右 |
移位 | << >> | 从左到右 |
关系 | < <= > >= | 从左到右 |
相等 | == != | 从左到右 |
位与 AND | & | 从左到右 |
位异或 XOR | ^ | 从左到右 |
位或 OR | | | 从左到右 |
逻辑与 AND | && | 从左到右 |
逻辑或 OR | || | 从左到右 |
条件 | ?: | 从右到左 |
赋值 | = += -= *= /= %=>>= <<= &= ^= |= | 从右到左 |
逗号 | , | 从左到右 |