C(数据类型)

C是有类型的语言

  • C语言的变量,必须:
  1. 在使用前定义,并且
  2. 确定类型
  • C以后的语言向两个方向发展
  1. C++和Java更强调类型,对类型的检查更严格
  2. JavaScript、Python、PHP不看重类型,甚至不需要事先定义

类型安全

  • 支持强类型的观点认为明确的类型有助于尽早发现程序中的简单错误
  • 反对强类型的观点认为过于强调类型迫使程序员面对底层、实现而非事物逻辑
  • 总的来说,早起语言强调类型,面向底层的语言强调类型
  • C语言需要类型,但是对类型的安全检查并不足够

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() 
{
int a;
a=6;
printf("sizeof(int)=%ld\n",sizeof(int));
printf("sizeof(a)=%ld",sizeof(a));    
return 0;    
 } 

占4个字节,1字节=8bit,即4个字节等于32bit(位)

double是8个字节,是int的两倍

long double是16个字节

sizeof

  • 是静态运算符,它的结果在编译时刻就决定呢
  • 不要在sizeof的括号里做运算,这些运算不会做的

#include <stdio.h>
int main() 
{
int a;
a=6;
printf("sizeof(a++)=%ld",sizeof(a++));    
return 0;    
 }   注:只判断a++的结果是什么类型,按类型输出字节数

#include <stdio.h>
int main() 
{
int a;
a=6;
printf("sizeof(a+1.0)=%ld",sizeof(a+1.0));    
return 0;    
 } 

注:a+1.0的结果是浮点数,是double类型

#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;    
 } 

整数

  • char:1字节(8比特)
  • short:两个字节
  • int:取决于编译器(CPU),通常的意义是“一个字”
  • long:取决于编译器(CPU),通常的意义是“一个字”
  • long long:8个字节

int就是表达CPU寄存器的大小和总线的大小,所以不同的计算机int不一样

比int小的,表达的是寄存器当中的某些位,比int大的可能是几个寄存器拼起来。

整数的内部表达:

  • 计算机内部一切都是二进制
  • 18         00010010
  • 0           00000000
  • -18        ?

如何表示负数:

  • 十进制用“-'号来表示负数,在做计算的时候

二进制负数

  • 一个字节可以表达的数:
  • 00000000-11111111(0-255)
  • 三种方案:
  • 1.仿照十进制,有一个特殊的标志表示负数
  • 2.取中间的数为0,如1000000表示0,比它小的表示负数,比它大的表示正数
  • 3.补码

实际上在计算机中采用补码的方案表示负数

  • 考虑-1,我们希望-1+1=0.如何能做到?
  • 0——00000000
  • 1——00000001
  • 11111111+00000001=100000000         100000000是9个bit,如果这个数是8bit,1会被丢掉,则结果变为00000000,为0。说明11111111就是-1
  • 因为0-1=-1,所以-1等于
  • (1)00000000-00000001=11111111   00000000前面添了一个1
  • 11111111被当做纯二进制看待时,是255,被当做补码看待时是-1
  • 同理,对于-a,其补码就是0-a,实际是2的n次方-a,n是这种类型的位数 
  • 补码的意义就是拿补码和原码可以加出一个溢出的“0”

数的范围

  • 对于一个字节(8位),可以表达的是:
  • 00000000-11111111
  • 其中
  • 00000000——0
  • 11111111-10000000——-1-128        注:11111111拿出来当做二进制来看时表示256,当做整数来看时是-1(当整数是一个字节时)
  • 00000001-01111111——1-127

#include <stdio.h>
int main() 
{
char c=255;
int i=255; 
printf("c=%d,c=%d",c,i);
return 0;    
 } 

char是一个字节,11111111,高位的1被占用呢,所以输出-1

int是四个字节,00000000 00000000 00000000 11111111,高位还是0,所以输出255

整数的范围

  • char:1字节:-128-127
  • short:2字节:-32768-32767
  • int :取决于编译器(CPU),通常的意义是“1个字”
  • long:4个字节
  • long long:8个字节

如果把这个数从计算机中拿出来也当做纯二进制数看待,用到unsigned

unsigned

  • 如果一个字面量常数想表达自己是unsigned,可以在后面加u或U
  • 255U
  • 用l或L表示long(long)
  • unsigned的初衷并非扩展数能表达的范围,而是为了做纯二进制运算,主要是为了移位

unsigned char c=255;      表示这个整数不以补码的形式表示负数,这个整数没负数部分,只有正数和零。意思不把高位1看作是补码,看作是纯二进制。

unsigned char c=255; 表达数的范围0-255

char c=255;表达数的范围-128-127

整数越界

整数的运算是以纯二进制的方式进行的,尽管整数的负数部分是以补码的方式表达的。为什么要补码?就是在计算时把它当做纯二进制数运算,算完以后正好有正确的结果。

整数是以纯二进制方式进行计算的,所以:

  • 11111111+1=100000000=0
  • 01111111+1=10000000=-128
  • 10000000-1=01111111=127

-128减1变成127

127加1变成-128

对于unsigned

255加1变成0

0减1变成255

int数据类型的最大数

整数的输入和输出

  • 只有两种形式:int 和long long                     所有小于int和int本身采用%d,比int大的用%ld表示
  • %d:int
  • %u:unsigned
  • %ld:long long
  • %lu:unsigned long long 

8进制和16进制

  • 一个以0开始的数字字面量是8进制
  • 一个以0X开始的数字字面量是8进制

选择整数类型:

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

浮点类型

类型字长范围有效数字
float32±(1.20x10^-38~3.40x10^38),0,±inf,nan7
double64

 

±(2.20x10^-308~1.79x10^308),0,±inf,nan

 

15

 

 

 

 

 

注:

  • ±inf表示正负无穷大
  • nan表示不是一个有效数字
  • 有效数字的意思是说,如float:只有七个数字是有效的,第八个是不准确的,第九个更不准确

浮点的输入输出

类型scanfprintf
float%f%f,%e
double%lf%f,%e

 

 

 

 

注:%e以科学计数法输出

科学计数法

输出精度

在%和f之间加上.n可以指定输出小数点后几位,这样的输出是做四舍五入的

如上:printf("%.30f\n",-0.0049) ;输出结果是-0.004899999999999999800000000000。说明-0.0049在计算机中里也是-0.0048999999999999998。

由此有:

浮点数的范围和精度

超过范围的浮点数

  • printf输出inf表示超过范围的浮点数:±∞
  • printf输出nan表示不存在的浮点数

浮点运算的精度

注:

  • 带小数点的的字面量是double而非float
  • float需要f或F后缀来表明身份

两个浮点数判断是否相等

  • f1==f2可能失败
  • 合理的方法是:fabs(f1-f2)<|e-|2            用两个浮点数差的绝对值和一个很小的数比较,这个数多小呢,通常比你要表达精度要小就好。如float,七位有效数字, 小于ex10-8就可以。

整数运算是精确的,带小数点的数运算是不精确的

浮点数的内部表达

如上一种表达:占满64位的浮点数。第一位表示±,11位表示指数部分,52位表示分数部分是多少

  • 浮点数内部不是二进制,而是一种编码的形式
  • 浮点数在计算时是由专用的硬件部件实现的
  • 计算double和float所用的部件是一样的

选择浮点类型

  • 如果没有特殊需求,只使用double
  • 现在CPU能直接对double做硬件运算,性能不会比float差,在64位的机器上,数据储存的速度也不比float慢

字符类型

  • char是一种整型,也是一种特殊的类型:字符。

这是因为

  • 用单引号表示的字符字面量:'a','1'
  • ''也是一个字符
  • printf和scanf里面用%c来输入输出字符

#include <stdio.h>
int main()
 {  
 int c;
 c=1;
 int d;
 d='1';
 if(c==d){
     printf("相等\n");
 }else{
     printf("不相等\n"); 
 } 
 printf("c=%d\n",c);
 printf("c=%d",d);
  return 0;
  } 

说明字符‘1’在计算机内部是49

每一个字符在计算机内部都有一个值表达它,这个值我们可以直接以整数的形式得到的

字符的输入输出

  • 如何输入'1'这个字符给char c?
  •  scanf("%c",&c);  输入1,得到49

  • scanf("%d",&i);c=i;得输入49

注:scanf以%d形式输入时,只能处理int,不能处理char,所以在这里定义了变量i

输入i=1,以%c输出变量c时,计算机找不到1所对应的字符是谁

输入49,以%c输出变量c时,计算机找到49所对应的字符是字符1

  • ‘1’对应的ASCII编码是49,所以当C==49时,它代表‘1’

混合输入

  • 有何不同?
  1. scanf("%d %c",&i,&c);
  2. scanf("%d%c",&i,&c);
  • scanf("%d %c",&i,&c);


   

  • scanf("%d%c",&i,&c);

空格的ASCII编码就是32

  1. scanf("%d %c",&i,&c);
  2. scanf("%d%c",&i,&c);   说明:
  • 无空格,整数只读到整数结束位置
  • 有空格,整数读完整数后,还要读完后面的空格

字符计算

  • 一个字符加一个数字得到ASCII码表中那个数之后的字符
  • 两个字符的减,得到它们在表中的距离

大小写转换

  • 字母在ASCII表中是顺序排列的
  • 大写字母和小写字母是分开排列的,并不在一起
  • 'a'-'A'可以得到两段之间的距离,于是
  1. a+'a'-'A'可以把一个大写字母变成小写字母
  2. a+'A'-'a'可以把一个小写字母变成大写字母

逃逸字符

  • 用来表达无法打印出来的控制字符或特殊字符,它由一个反斜杠"\"开头,后面跟上另一个字符,这两个字符合起来,组成了一个字符。

\"表示双引号,是一个字符。之所以这么做,是因为在双引号里不能直接出现双引号,不然会以为"如输入\"是一个字符串

逃逸字符

字符意义字符意义
\b回退一格\"双引号
\t到下一个表格位\'单引号
\n换行\\反斜杠本身
\r回车  

 

 

 

 

 

 

  1. 回退一格

2.到下一个表格位

  • 每行的固定位置
  • 一个\t使得输出从下一个制表位开始
  • 用\t才能使得上下两行对齐

TAB键指的是一行中固定的位置,而不是固定大小的字符数量

类型转换

自动类型转换

  • 当运算符的两边出现不一致的类型时,会自动转换成较大的类型
  • 大的意思是指能表达的数的范围更大
  • char——short——int——long——long long                                 char遇到short,会自动转换成short
  • int——float——double                                                                  int遇见float,,会自动转换成float
  • 对于printf,任何小于int的类型会被转换成int;float会被转换成double                     我们在printf()里用%f足以输出double
  • 但是scanf不会。如要输入short,需要%hd

强制类型转换

  • 要把一个量强制转化成另一个类型(通常是较小的类型),需要:
  • (类型)值
  • 比如
  1. (int)10.2
  2. (short)32
  • 注意这时候的安全性,小的变量不总能表达大的量
  • 如:

注:强制类型转换只是从那个变量计算出了一个新的类型的值,它并不改变那个变量,无论是值还是类型都不改变

  • 强制类型转换的优先级高于四则运算

double a=1.0;

double b=2.0;

int i=(int)a/b;            会先做(int)a,再用(int)a的值/b

正确做法:int i=(int)(a/b);

逻辑类型

bool

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

逻辑运算

  • 逻辑运算是对逻辑量进行的运算,结果只有0或1;
  • 逻辑量是关系运算或逻辑运算的结果
运算符描述示例结果
逻辑非!a如果a是true,结果就是false。如果a是false,结果就是true。
&&逻辑与a&&b如果a和b都是true,结果就是true,否则就是false
||逻辑或a||b如果a和b有一个是true,结果就是true。如果a和b两个都是false,结果就是false。

 

 

 

 

 

 

TRY

  • 如果要表达数学中的区间,如:x∈(4,6)或x∈[4,6],应该如何写C的表达式?

4<x<6这样的式子,不是C能正确计算的式子,因为4<x的结果是一个逻辑值(0或1)

正确表达式:x>4&&x<6

  • 如何判断一个字符c是否是大写字母呢?

c>='A'&&c<='Z'

优先级

  • !>&&>||
优先级运算符结合性
1()从左到右
2!+ - ++ --从右到左(单目的+和-)
3*/%从左到右
4+-从左到右
5<<==>>=从左到右
6== !=从左到右
7&&从左到右
8||从左到右
9=+=-=/=*=%=从右到左

 

 

 

 

 

 

 

 

 

 

短路:

逻辑运算是自左向右进行的,如果左边的结果已经能够决定结果呢,就不会做右边的计算。

  • a==6&&b==1
  • a==6&&b+=1
  • 对于&&,如果左边是false时就不做右边呢
  • 对于||,如果左边是true时就不做右边呢
  • 不要把赋值,包括复合赋值组合进表达式。

条件和逗号运算

条件运算符

  • count=(count>20)?count-10:count+10;
  • 条件、条件满足时的值和条件不满足时的值

 if(count>20){
     count=count-10;
 }else{
     count=count+10;
 }

优先级:

  • 条件运算符的优先级高于赋值运算符,但是低于其他运算符。

逗号运算

逗号用来连接两个表达式,并以其右边表达式的值作为它的结果。逗号的优先级是所有的运算符中最低的,所以它两边的表达式会先计算;逗号的组合关系是自左向右,所以左边的表达式会先计算,而右边表达式的值就留下来作为逗号运算的结果。

在for当中使用,

for(i=0,j=0;i<j;i++,j++)            ;前有多个表达式,用,号运算符

 

 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值