本节课理论知识较多。
- C语言有哪些数据类型?有哪些整数类型?有哪些浮点类型?
- 各种数据类型如何表示?输入输出格式化有哪些?
- 各种类型大小是多少?范围是多少?
- 如何选择整型类型和浮点类型?
1. 数据类型
学习是一个日积月累的过程,从多模仿,到多看多想,最后到多用。
数值类型分为整型(整数)和浮点型(小数)。按照表示数字范围的从大到小
- 整数分为五类:字符型(
char
)、短整型(short
)、整型(int
)、长整型(long
)和长长整型(long long
) - 浮点型分三类:单精度型(
float
)、双精度型(double
)和长双精度型(long double
)
1.1 获取类型大小
关键字sizeof
:查看变量或者类型大小
int n;
printf("%d",sizeof(int));
printf("%d",sizeof(n));
上面的括号不是必须的,但是建议带上。所以也可以如下表示:
int n;
printf("%d",sizeof int);
printf("%d",sizeof n);
2.2 各种类型的大小
printf("sizeof(char)=%d\n",sizeof(char));
printf("sizeof(short)=%d\n",sizeof(short));
printf("sizeof(int)=%d\n",sizeof(int));
printf("sizeof(long)=%d\n",sizeof(long));
printf("sizeof(long long)=%d\n",sizeof(long long));
printf("sizeof(float)=%d\n",sizeof(float));
printf("sizeof(double)=%d\n",sizeof(double));
printf("sizeof(long double)=%d\n",sizeof(long double));
在编译命令加上选项-m32
再试一下。
通常有些类型大小并不是固定的,计算机硬件、操作系统和编译器都会影响类型的大小。通常类型大小有如下规律:
char < short < int < float < double
int <= long <= long long
在常用的计算机硬件和操作系统中,各种类型的大小如下表所示:
2.3 字节
sizeof
获得数据的单位是Byte(字节)。Byte(字节)是计量存储容量的一种计量单位,一个字节是8位二进制,可容纳256个数字。一个ASCII字符就是一个字节。
除了Byte(字节),还有其他常用存储容量单位
No. | 单位 | 说明 |
---|---|---|
1 | bit(比特/位) | 计算机中的最小数据单位,1个Byte(字节)=8个bit(比特/位) |
2 | word(字) | 计算机CPU一次操作处理实际数据最大位数,我们常说的32/64位就是计算机的字。 |
3 | KB | 1KB=1024B |
4 | MB | 1MB=1024KB |
5 | GB | 1GB=1024MB |
6 | TB | 1TB=1024GB |
有时,我们用
B
表示Byte(字节),用b
表示bit(比特/位),注意两者区别。
2.4 输入输出格式化
No. | 类型 | 占位符 |
---|---|---|
1 | char |
%c |
2 | short |
%hd |
3 | int |
%d |
4 | long |
%ld |
5 | long long |
%lld |
6 | float |
%f |
7 | double |
%lf |
8 | long double |
%Lf |
double
的输入占位符必须是%lf
,输出占位符可以是%f
。
2. 整数类型
2.1 表示范围
每种数据类型大小不同,各自表示数据范围也不同。下面的常用类型的范围。
No. | 类型 | 数字范围 | 表示 |
---|---|---|---|
1 | char |
-128 ~127
|
-27~27-1 |
2 | short |
-32 768 ~32 767 约万 |
-215~215-1 |
3 | int |
-2 147 483 648 ~2 147 483 647 约亿 |
-231~231-1 |
4 | long long |
-9 223 372 036 854 775 808 ~9 223 372 036 854 775 807 约亿 |
-263~263-1 |
上面的是通常范围(32位下),实际上有些情况略有出入。总之,类型的表示范围与类型大小存在如下关系:
其中,是类型大小。
2.2 无符号整型
在一些特殊情况下,数据只用0
和整数,不存在负数,这时可以使用无符号整型unsigned
。无符号整型只是在原来的整型前加上关键字unsigned
。因为没有负数,所以数值的表示范围扩大了一倍。
No. | 类型 | 数字范围 | 表示 |
---|---|---|---|
1 | unsigned char |
0 ~255
|
0~28-1 |
2 | unsigned short |
0 ~65 535 约6万 |
0~216-1 |
3 | unsigned int |
0 ~4 294 967 295 约43亿 |
0~232-1 |
4 | unsigned long long |
0 ~18 446 744 073 709 551 615
|
0~264-1 |
类型的表示范围与类型大小存在如下关系:
其中,是类型大小。
输入输出无符号整型格式
No. | 类型 | 占位符 |
---|---|---|
1 | char |
%u |
2 | short |
%hu |
3 | int |
%u |
4 | long |
%lu |
5 | long long |
%llu |
2.3 整型类型选择
整型类型很多,通常遵循下面的使用规则:
- 大多数情况下使用
int
。 - 如果
int
范围不够,使用long long
。 - 避免使用
long
。 - 谨慎使用
unsigned
。
3. 浮点类型
3.1 浮点数的范围
运行下面程序,分析执行结果:
#include <stdio.h>
int main(){
printf("1.0/0.0 = %f\n",1.0/0.0);
printf("-1.0/0.0 = %f\n",-1.0/0.0);
printf("0.0/0.0 = %f\n",0.0/0.0);
return 0;
}
当浮点数超出可表示的范围,会有如下值。
No. | 输出 | 含义 |
---|---|---|
1 | inf |
表示正无穷大 |
2 | -inf |
表示负无穷大 |
3 | nan |
不存在 |
3.2 浮点数的精度
- 设计上的精度问题
运行下面程序,分析执行结果:
#include <stdio.h>
int main(){
float f = 123456789.0;
double d = 123456789.0;
printf("f=%f\n" ,f);
printf("d=%lf\n",d);
return 0;
}
计算机浮点数存在精度问题。
No. | 类型 | 数字范围 | 有效数字 |
---|---|---|---|
1 | float |
-3.4E+38 ~3.4E+38
|
6~7 |
2 | double |
-1.7E-308 ~1.7E+308
|
15~16 |
3 | long double |
-1.2E-4932 ~1.2E+4932
|
18~19 |
注意:浮点类型没有无符号unsigned
类型。
- 运算中的精度问题
运行下面程序,分析执行结果:
#include <stdio.h>
int main(){
float a = 10.2;
float b = 9;
float c = a - b;
printf("%f - %f = %f\n", a,b,c);
return 0;
}
上面结果看似正确,把程序改成如下:
#include <stdio.h>
int main(){
float a = 10.2;
float b = 9;
float c = a - b;
if(c == 1.2){
printf("%f == 1.2",c);
}else{
printf("%f != 1.2",c);
}
return 0;
}
以7位有效数组打印运算结果。
#include <stdio.h>
int main(){
float a = 10.2;
float b = 9;
float c = a - b;
printf("%.7f - %.7f = %.7f\n", a,b,c);
return 0;
}
发现运算中存在精度缺失。
如何比较浮点数?使用最小误差。
#include <stdio.h>
int main(){
float a = 10.2;
float b = 9;
float c = a - b;
if(fabs(c - 1.2) < 0.000001){
printf("%f == 1.2\n",c);
}else{
printf("%f != 1.2\n",c);
}
return 0;
}
在误差范围内认为相等。即绝对值差小于精度最小值。
float
浮点数误差通常为(6位有效数字)。
double
浮点数误差通常为(15位有效数字)。
3.3 浮点类型选择
浮点类型有三种,通常遵循下面的使用规则:
- 大多数情况下使用
double
。 - 尽量不要使用
float
。 - 过程运算可以使用
long double
。
问题
- 既然浮点数这么不准确,为什么还需要?
浮点数通过损失精度,获取更大的表示范围。 - 试一试:整数除以零会有什么结果
#include <stdio.h>
int main(){
printf("1/0 = %d\n",1/0);
return 0;
}
4. 字符类型
字符类型是一个特殊类型,是整型的一种。使用单引号表示字符字面量,例如:字母'a'
、数字'1'
、空字符''
、转义字符\n
。
通常使用%c
作为格式化占位符输入输出,有时也可以使用%d
输出字符对应ASCII编码。
- 打印字符
#include <stdio.h>
int main(){
char c='1';
printf("%c\n%d\n",c,c);
return 0;
}
4.1 ASCII编码
ASCII编码使用7 位二进制数(剩下的1位二进制为0)来表示所有的大写和小写字母,数字0 到9、标点符号, 以及在美式英语中使用的特殊控制字符。
ASCII表的特点:
- 字母在ASCII表中是顺序排列的。
- 大写字母和小写字母是分开排列的。
C语言中字符即数字。
printf("%d\n",'a'); printf("%c\n",97);
4.2 运算
- 字符类型可以像整型一样参与运算。
例如:
#include <stdio.h>
int main(){
char a='a';
printf("%c\n%c\n",a,a+1);
return 0;
}
字符类型操作含义:
- 一个字符加上一个数字得到ASCII表中对应新字符。
- 两个字符相减,得到这两个字符在表中的距离。
实例:
- 分别打印出26个大写字母和小写字母。
- 把一个字符串整型数字转化成整型数字。例如:
"1234"
转发成1234
。 - 判断一个字符串是否存在满足标识符命名规则。
- 大小写转换
4.3 转义字符/逃逸字符
在ASCII表中,除了常见的字符(如:大小写字母、数字等),还包含一些无法打印出来的控制字符或特殊字符。这些字符以反斜线\
开头,后面接着一个字符,这种字符被称作转义字符/逃逸字符。
- 常用的转义字符/逃逸字符
字符 | 含义 | 字符 | 含义 |
---|---|---|---|
\' |
单引号 | \" |
双引号 |
\r |
回车 | \n |
换行 |
\b |
退格符 | \f |
翻页符 |
\t |
表格符 | \\ |
反斜线符 |
5. 布尔类型
在C99中新增bool
类型表示逻辑值,它只有两种值(true
和false
)。使用前需要加上头文件stdbool.h
。
6. 数据转换
6.1 自动类型转换
当运算符左右两边操作数的类型不一致时,会自动转换成较大类型。
- 整型:
char
→short
→int
→long
→long long
- 浮点型:
int
→float
→double
→long double
6.2 强制类型转换
当把一个较大的类型转换成较小的类型,需要强制转换。
强制转换语法
(转换后的类型)值
例如:
printf("%d\n",(int)3.14);
有时,整型转浮点型也需要强制转换。
例如:
printf("%f\n",(double)1/2);
其中,浮点数转整数采用的是截断方式。
7.练习
- 下面代码输出结果
int main(){
for(char i =0; i < 256; ++i){
printf("%d\n", i);
}
}