第5周:数据类型
标签(空格分隔): C
5.1.1 数据类型:数据类型
C是有类型的语言
C语言的变量,必须:在使用前定义,并且确定类型 C以后的语言向两个方向发展:
C++/Java更强调类型,对类型的检查更严格 JavaScript、Python、PHP不看重类型,甚至不需要事先定义
C语言的类型
整数
char、short、int、long、long long 浮点数
逻辑
指针 自定义类型
类型有何不同
类型名称:int、long、double 输入输出时的格式化:%d、%ld、%lf 所表达的数的范围:char<short<int<float<double 内存中所占据的大小:1字节到16个字节 内存中的表达形式:二进制数(补码)、编码
sizeof
是一个运算符,给出某个类型或变量在内存中所占据的字节数
#include <stdio.h>
int main()
{
printf("sizeof(int)=%ld\n", sizeof(int));
printf("sizeof(double)=%ld\n", sizeof(double));
printf("sizeof(long double)=%ld\n", sizeof(long double));
return 0;
}
sizeof(int)=4
sizeof(double)=8
sizeof(long double)=16
是一个静态运算符,它的结果在编译时刻就决定了 不要在sizeof的括号里做运算,这些运算是不会做的
#include <stdio.h>
int main()
{
int a;
a = 6;
printf("sizeof(a)=%ld\n", sizeof(a++));
printf("sizeof(a+1.0)=%ld\n", sizeof(a+1.0));
printf("a=%d\n", a);
return 0;
}
sizeof(a)=4
sizeof(a+1.0)=8
a=6
5.1.2 数据类型:整数类型
整数
#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)=4
sizeof(long long)=8
char:1字节(8比特):-128 ~ 127 short:2字节:-32768 ~ 32767 int:取决于编译器(CPU),通常的意义是“1个字”(int是用来表达寄存器的) long:取决于编译器(CPU),通常的意义是“1个字” long long:8字节
5.1.3 数据类型:整数的内部表达
整数的内部表达
计算机内部的一切都是二进制
18 --> 00010010 0 --> 00000000 -18 -->?
二进制负数
1个字节可以表达的数:
00000000 – 11111111(0 - 255) 三种方案:
仿照十进制,有一个特殊的标志表示负数 取中间的数为0,如10000000表示0,比它小的是负数,比它大的是正数 补码
补码
考虑 -1,我们希望 -1 + 1 --> 0。如何能做到?
0 --> 00000000 1 --> 00000001 11111111 + 00000001–>100000000 因为 0 - 1 --> -1。所以,-1 =
(1)00000000 - 00000001 --> 11111111 11111111被当做纯二进制看待时,是255,被当做补码看待时是 -1 同理,对于-a,其补码就是 0 - a,实际上是2^n - a,n是这种类型的位数 补码的意义就是拿补码和原码可以加出一个溢出的“零”
5.1.4 数据类型:整数的范围
数的范围
对于一个字节(8位),可以表达的是:
其中
00000000 --> 0 11111111 ~ 10000000 --> -1 ~ -128 00000001 ~ 01111111 --> 1 ~ 127
#include <stdio.h>
int main()
{
char c = 255;
int i = 255;
printf("c=%d,i=%d\n", c, i);
return 0;
}
c=-1,i=255
unsigned
如果一个字面量常数想要表达自己是unsigned,可以在后面加u或U、
用l或L表示long(long) *unsigned的初衷并非扩展数能表达的范围,而是为了做纯二进制运算,主要是为了移位
整数越界
整数是以纯二进制方式进行计算的,所以:
11111111 + 1 --> 100000000 --> 0 01111111 + 1 --> 10000000 --> -128 10000000 - 1 --> 01111111 --> 127
5.1.5 数据类型:整数的格式化
整数的输入输出
只有两种形式:int或long long
%d: int %u: unsigned %ld: long long %lu: unsigned long long
#include <stdio.h>
int main()
{
char c = -1;
int i = -1;
printf("c=%u,i=%u\n", c, i);
return 0;
}
c=4294967295,i=4294967295
8进制和16进制
一个以0开始的数字字面量是8进制 一个以0x开始的数字字面量是16进制 %o用于8进制,%x用于16进制 8进制和16进制只是如何把数字表达为字符串,与内部如何表达数字无关
#include <stdio.h>
int main()
{
char c = 012;
int i = 0x12;
printf("c=%d,i=%d\n", c, i);
return 0;
}
c=10,i=18
#include <stdio.h>
int main()
{
char c = 012;
int i = 0x12;
int j = 0x1A;
printf("c=%o,i=%x,j=%X,j=%x\n", c, i, j, j);
return 0;
}
c=12,i=12,j=1A,j=1a
16进制很适合表达二进制数据,因为4为二进制正好是一个16进制位 8进制的意味数字正好表达3位为二进制
5.1.6 数据类型:选择整数类型
选择整数类型
为什么整数要有很多种?
没有特殊需要,就选择int
现在CPU的字长普遍为32位或64位,一次内存读写就是一个int,一次计算也是一个int,选择更短的类型不会更快,甚至可能更慢 现代编译器一般会设置内存对齐,所以更短的类型实际在内存中可能也占据一个int的大小(虽然sizeof告诉)你更小) unsigned与否只是输出的不同,内部计算是一样的
5.1.7 数据类型:浮点类型
浮点类型
类型 字长 范围 有效数字 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
浮点的输入输出
类型 scanf printf float %f %f,%e double %lf %f,%e
科学计数法
-5.67E+16
可选的 + 或 - 符号 小数点也是可选的 可用 e 或 E 符号可用是 - 或 + 也可以省略(表示+) 整个词不能有空格
输出精度
在 % 和 f 之间加上 .n 可指定输出小数点后几位,这样的输出是做四舍五入的
#include <stdio.h>
int main()
{
printf("%.3f\n",-0.0049);
printf("%.30f\n",-0.0049);
printf("%.3f\n",-0.00049);
return 0;
}
-0.005
-0.004899999999999999800000000000
-0.000
5.1.8 数据类型:浮点的范围和精度
超过范围的浮点数
printf输出Iinf表示超过范围的浮点数:+∞ printf输出nan表示不存在的浮点数
浮点运算的精度
#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("不相等!c=%.10f,或%f\n",c,c);
}
不相等!c=2.4679999352,或2.468000
带小数点的字面量是double而非float float需要用f或F后缀来表明身份 f1 == f2 可能失败 fabs(f1-f2) < 1e-12
选择浮点类型
如果没有特殊需要,只使用double 现代CPU能直接对double做硬件运算,性能不会比float差,在64位的机器上,数据存储的速度也不比float慢
5.1.9 数据类型:字符类型**
字符类型
char是一种整数,也是一种特殊的类型:字符。这是因为:
用单引号表示的字符字面量:‘a’,‘1’ ''也是一个字符 printf 和 scanf 里用%c来输入输出字符
字符输入输出
#include <stdio.h>
int main()
{
char c;
char d;
c = 1;
d = '1';
//判断整数和字符是否相等
if (c==d)
printf("相等\n");
else
printf("不相等\n");
//输出c,d
printf("c=%d\n",c);
printf("d=%d\n",d);
//输入%c
char e;
scanf("%c",&e);
printf("e=%d\n",e);
printf("e='%c'\n",e);
return 0;
}
不相等
c=1
d=49
e=49
e='1'
字符计算
一个字符加一个数字得到ASCII码表中那个数之后的字符 两个字符相减,得到它们在表中的距离
大小写转换
字母在ASCII表中是顺序排列的 大写字母和小写字母是分开排列的,并不在一起 ‘a’-‘A’可以得到两段之间的距离,于是
a+‘a’-‘A’可以把一个大写字母变成小写字母,而 a+‘A’-‘a’可以把一个小写字母变成大写字母
5.1.10 数据类型:逃逸字符
逃逸字符
用来表达无法印出来的控制字符或特殊字符,它由一个反斜杠“\”开头,后面跟上另一个字符,这两个字符合起来,组成了另一个字符
字符 意义 字符 意义 \b 回退一格 " 双引号 \t 到下一个表格位 ’ 单引号 \n 换行 \ \ 反斜杠本身 \r 回车
制表位
每行的固定位置 一个\t使得输出从下一个制表位开始 用\t才能使得上下两行对齐
#include <stdio.h>
int main()
{
printf("123\b\n456\n");
printf("123\bA\n456\n");
printf("123\t456\n");
printf("12\t456\n");
return 0;
}
123
456
12A
456
123 456
12 456
5.1.11 数据类型:类型转换
自动类型
当运算符的两边出现不一致的类型时,会自动转换成较大的类型
大的意思是能表达的数的范围更大 char–>short–>int–>long–>long long int–>float–>double 对于printf,任何小于int的类型会被转换成int;float会被转换成double 但是scanf不会,要输入short,需要%hd
强制类型转换
要把一个量强制转换成另一个类型(通常是较小的类型),需要:
比如:
注意这时候的安全性,小的变量不总能表达大的量 只是从那个变量计算出了一个新的类型的值,它并不改变那个变量,无论是值还是类型都不改变
5.2.1 其他运算:逻辑类型
bool
#include <stdbool.h>
5.2.2 其他运算:逻辑运算
逻辑运算是对逻辑量进行的运算,结果只有0或1 逻辑量是关系运算或逻辑运算的结果
运算符 描述 示例 结果 ! 逻辑非 !a 如果a是true结果就是false,如果a是false结果就是true && 逻辑与 a&&b 如果a和b都是true,结果就是true;否则就是false ll 逻辑或 a ll b 如果a和b有一个是true,结果为true,两个都是false,结果为false
短路
逻辑运算是自左向右进行的,如果左边的结果已经能够决定结果了,就不会做右边的计算
对于&&,左边的false时就不做右边了 对于||,左边是true时就不做右边了 不要把赋值,包括复合赋值组合仅表达式
5.2.3 其他运算:条件运算与逗号运算
条件运算符
条件运算符的优先级高于赋值运算符,但是低于其他运算符
逗号运算
逗号运算用来连接两个表达式,并以其右边的表达式的值作为它的结果。逗号的优先级是所有的运算符中最低的,所以它两边的表达式会先计算;逗号的组合关系是自左向右,所以左边的表达式会先计算,而右边的表达式的值就留下来作为逗号运算的结果。 在for中使用