C程序设计语言:数据类型

第5周:数据类型

标签(空格分隔): C


5.1.1 数据类型:数据类型

C是有类型的语言
  • C语言的变量,必须:在使用前定义,并且确定类型
  • C以后的语言向两个方向发展:
    • C++/Java更强调类型,对类型的检查更严格
    • JavaScript、Python、PHP不看重类型,甚至不需要事先定义
C语言的类型
  • 整数
    • char、short、int、long、long long
  • 浮点数
    • float、double、long double
  • 逻辑
    • bool
  • 指针
  • 自定义类型
类型有何不同
  • 类型名称:int、long、double
  • 输入输出时的格式化:%d、%ld、%lf
  • 所表达的数的范围:char<short<int<float<double
  • 内存中所占据的大小:1字节到16个字节
  • 内存中的表达形式:二进制数(补码)、编码
sizeof
  • 是一个运算符,给出某个类型或变量在内存中所占据的字节数
    • sizeof(int)
    • sizeof(i)
#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 - 11111111
  • 其中
    • 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、
    • 255U
  • 用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位为二进制
    • 因为早期计算机的字长是12的倍数,而非8

5.1.6 数据类型:选择整数类型

选择整数类型
  • 为什么整数要有很多种?
    • 为了准确表达内存,做底层程序的需要
  • 没有特殊需要,就选择int
    • 现在CPU的字长普遍为32位或64位,一次内存读写就是一个int,一次计算也是一个int,选择更短的类型不会更快,甚至可能更慢
    • 现代编译器一般会设置内存对齐,所以更短的类型实际在内存中可能也占据一个int的大小(虽然sizeof告诉)你更小)
  • unsigned与否只是输出的不同,内部计算是一样的

5.1.7 数据类型:浮点类型

浮点类型
类型字长范围有效数字
float32±(1.20*10-38~3.40*1038),0,±inf,nan7
double64±(2.2*10-308~1.79*10308),0,±inf,nan15
浮点的输入输出
类型scanfprintf
float%f%f,%e
double%lf%f,%e
  • %.16f:在小数点后输出16位数字
科学计数法
  • -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
强制类型转换
  • 要把一个量强制转换成另一个类型(通常是较小的类型),需要:
    • (类型)值
  • 比如:
    • (int)10.2
    • (short)32
  • 注意这时候的安全性,小的变量不总能表达大的量
  • 只是从那个变量计算出了一个新的类型的值,它并不改变那个变量,无论是值还是类型都不改变

5.2.1 其他运算:逻辑类型

bool
#include <stdbool.h>
  • 之后就可以使用bool和true、false

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
  • 优先级:!>&&>||
短路
  • 逻辑运算是自左向右进行的,如果左边的结果已经能够决定结果了,就不会做右边的计算
    • a6 && b1
  • 对于&&,左边的false时就不做右边了
  • 对于||,左边是true时就不做右边了
  • 不要把赋值,包括复合赋值组合仅表达式

5.2.3 其他运算:条件运算与逗号运算

条件运算符
  • 条件运算符的优先级高于赋值运算符,但是低于其他运算符
逗号运算
  • 逗号运算用来连接两个表达式,并以其右边的表达式的值作为它的结果。逗号的优先级是所有的运算符中最低的,所以它两边的表达式会先计算;逗号的组合关系是自左向右,所以左边的表达式会先计算,而右边的表达式的值就留下来作为逗号运算的结果。
  • 在for中使用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值