数据类型
C语言是有类型的语言
C语言的变量必须在使用前定义并且确定类型
错误示例:
cpp
#include <stdio.h>
int main()
{
a = 6;
return 0;
}
修正:
cpp
#include <stdio.h>
int main()
{
int a;
a = 6;
return 0;
}
C语言以后的语言发展方向
C++/Java更强调类型,对类型的检查更严格
JavaScript、Python、PHP不看重类型,甚至不需要事先定义
类型安全
- 支持强类型的观点认为明确的类型有助于尽早发现程序中的简单错误
- 反对强类型的观点认为过于强调类型迫使程序员面对底层、实现而非事务逻辑
- 总的来说,早期语言强调类型,面向底层的语言强调类型
- C语言需要类型,但是对类型安全的检查并不足够
C语言的类型
整数:char、short、int、long、long long
浮点数:float、double、long double
逻辑:bool
指针
自定义类型
(加蓝的是C99的类型,前四种是C语言的基础类型)
类型有何不同
类型名称:int、long、double
输入输出时的格式化:%d、%ld、%lf
所表达的数的范围:char < short < int < float < double
内存中所占据的大小:1个字节到16个字节
内存中的表达形式:整数------二进制数(补码)、浮点数------编码(不能直接运算)
sizeof:是一个运算符,给出某个类型或变量在内存中所占据的字节数
- sizeof是静态运算符,他的结果在编译时可就决定了
- 不要在sizeof的括号里做运算,没有意义
整数类型
用sizeof查看整数
cpp
#include <stdio.h>
int main()
{
printf("sizeof(char)=%ld\n", sizeof(char));
printf("sizeof(short)=%ld\n", sizeof(short));
printf("sizeof(int)=%ld\n", sizeof(int));
printf("sizeof(long)=%ld\n", sizeof(long));
printf("sizeof(long long)=%ld\n", sizeof(long long));
return 0;
}
sizeof(char)=1
sizeof(short)=2
sizeof(int)=4
sizeof(long)=8
sizeof(long long)=8
(64位编译器结果)
char:1字节(-128~127)
short:2字节(-32768~32767)
int:取决于编译器,通常是"1个字"
long:取决于编译器,通常是"1个字"
long long:8字节
1字节=8比特
整数的内部表达
计算机内部一切都是二进制,只是以什么方式看待它
如何表示负数
十进制用"-"表示负数,在做计算时
12+(-18)
12-18
12-(-18)
12+18
12*(-18)
-(12*18)
12/(-18)
-(12/18)
二进制负数
一个字节可以表达的数:00000000---11111111(0---255)
三种方案:
- 仿照十进制,有一个特殊的标志表示负数
- 取中间的数为0,如10000000表示0,比它小的是负数,比它大的是正数
- 补码
方案一:在计算机的内部设计上面会比较复杂
方案二:程序在输入输出时变得复杂
补码
在计算机中,00000001+11111111=(1)00000000,但如果数是8比特的,最前面的1就会被丢掉,剩下的结果表示为0。所以如果让00000001表示1,让11111111表示-1,那么相加就等于0
- 因此,11111111当作纯二进制看待时是255,当作补码看待时是-1
- 同理,对于-a,其补码就是0-a,实际是
-a,n是这种类型的位数
补码的意义:拿补码和原码可以加出一个溢出的0
整数的范围
数的范围
对于一个字节(8位):00000000---11111111
其中:000000000、11111111---10000000
-1----128、00000001---01111111
1---127
unsigned:如果一个字面量常数想要表达自己是unsigned,可以在后面加u或U
(表达long也可以在后面加l或L)
*unsigned的初衷并非扩展数能表达的范围,而是为了纯做二进制运算,主要是为了移位
整数的格式化
整数的输入输出
只有两种形式:int或long
%d:int、%u:unsigned、%ld:long long、%lu:unsigned long long
8进制和16进制:%o用于8进制,%x用于16进制
选择整数类型
- 为什么整数类型有很多:
为了准确表达内存,做底层程序的需要
- 没有特殊需要,就选择int
- unsigned与否只是输出的不同,内部计算是一样的
浮点类型
浮点类型
类型 | 字长 | 有效数字 |
---|---|---|
float | 32 | 7 |
double | 64 | 15 |
浮点的输入输出
类型 | scanf | printf |
---|---|---|
float | %f | %f, %e |
double | %lf | %f, %e |
%e:会输出为科学计数法的形式
eg.9.21e+99表示9.21×
输出精度
在%和f之间加上.n可以指定输出小数点后几位,这样的输出是做四舍五入的
printf("%.3f\n", -0.0049);
printf("%.30\n", -0.0049);
printf("%.3f\n", -0.00049);
浮点的范围和精度
超过范围的浮点数
printf输出inf表示超过范围的浮点数:
printf输出nan表示不存在的浮点数
浮点运算的精度
cpp
#include <stdio.h>
int main()
{
float a,b,c;
a=1.345f;
b=1.123f;
c=a+b;
if(c==2.468)
printf("相等\n");
else
printf("不相等\n");
return 0;
}
结果:不相等
- 带小数点的字面量是double而非float
- float需要用f或F后缀来表明身份
浮点数是不精确的
浮点数的内部表达
浮点数在计算时是由专用的硬件部件实现的
计算double和float所用的部件是一样的
选择浮点类型
如果没有特殊需要,只使用double
字符类型
字符类型
char是一种整数,也是一种特殊的类型:字符
用单引号表示的字符字面量:'a' , '1'
"也是一个字符
printf和scanf里用%c来输入输出字符
将'1'赋给char c:
cpp
#include <stdio.h>
int main()
{
char c;
char d;
c = 1;
d = '1';
if ( c==d ){
printf("相等\n");
} else {
printf("不相等\n");
}
return 0;
}
结果:不相等
*scanf只能处理int,不能处理char
混合输入
有什么不同:
scanf("%d %c", &i, &c);
scanf("%d%c", &i, &c);
百分号后没有空格,整数只能读到整数结束为止
字符计算
char c = 'A';
c++;
pritnf("%c\n", c);
>>B
int i = 'Z' - 'A';printf("%d\n", i);
- 一个字符加一个数字得到ASCII码表中那个数之后的字符
- 两个字符的减,得到他们在表中的距离
大小写转换
字母在ASCII表中是顺序排列的
大写字母和小写字母是分开排列的,并不在一起
'a'-'A'可以得到两段之间的距离
逃逸字符
用来表达无法印出来的控制字符或特殊字符,它由一个反斜杠"\"开头,后面跟上另一个字符,这两个字符合起来,组成了一个字符
printf("请分别输入身高的英尺和英寸,"
"如输入\"5 7\"表示5英尺7英寸:");
字符 | 意义 | 字符 | 意义 |
---|---|---|---|
\b | 回退一格 | \* | 双引号 |
\t | 到下一个表格位 | \' | 单引号 |
\n | 换行 | \\ | 反斜杠本身 |
\r | 回车 |
printf("123\bA\n456\n");
>>12A
456
制表位
- 每行的固定位置
- 一个\t使得输出从下一个制表位开始
- 用\t才能使得上下两行对齐
类型转换
自动类型转换
- 当运算符的两边出现不一致的类型,会自动转换成较大的类型(大的意思是能表达的属的范围更大)
- 对于printf,任何小于int的类型会被转换成int;float会被转换成double。但是scanf不会,要输入short,需要%hd
强制类型转换
需要把一个量强制转换成另一个类型(通常是较小的类型),需要:(类型)值
eg. (int)9.21 (short)99
注意:安全性,小的变量不能总表达大的变量
eg. (short)32768 >> -32768
- 只是从那个变量计算出了一个新的类型的值,它并不改变那个变量,无论是值还是类型
- 强制类型转换优先级高于四则运算