C语言学习笔记(浙大翁恺版)第六周(1)

6.1.1 C语言其他的基本数据类型

 sizeof:属于(静态)运算符,可以给出某个类型或者变量在内存里占据的字节数。其结果在编译的时候就已经确定,与程序执行阶段无关,所以不能用来计算。但是可以放表达式,比如

int a;

sizeof(a+1.0)结果为->8,因为C自动转换了这个表达式,其类型为double,所以字节长度是8,并非真正的计算

比如:sizeof(int)   sizeof(i)

6.1.2 整数类型

 

 int字节长度实际上是寄存器存放的字长,比如32位是32bit=4字节,64bit

6.1.3 整数的内部表达

那么整数是怎么在计算机内部进行表达的呢?如果是负数又该怎么表达呢? 

当然,不管是整数、浮点数还是什么乱七八糟数,计算机只能看懂二进制数!所以毫无疑义是二进制数,类型的意义,在于我们以什么方式去看待它

那么再回到负数的问题,在C中我们将减法异化为带负号的加法,用独立的方式来表示一个负数,比如15-8 -> 15+(-8) -> 7; 15 - (-8) -> 15+8 -> 23 ; 15*(-8) -> -(15*8);

一个字节为8bit,可以表示二进制数从00000000到11111111,也就是十进制的0~255。

表示负数的方案:

 第一种,需要额外一个变量来控制整个加减,而第二种每次加减都需要与中间变量进行比较,因此都不是很简便。实际选用了第三种方式。

那么我们就思考如何表示-1,让1+(-1)=0?

00000001+=00000000。即?为11111111。和实际上为100000000,但是如果限制了8bit,多出来的最高位就会被舍弃。也就得到了00000000.

也可以用另外一种方式来思考,0-1就得到了-1,那么0向高位借1,即为(1)00000000 - 00000001,也可以得到11111111。

因此可以得知,对于纯二进制数,11111111为255,但对于补码来说它是-1.

同理对于任意数-a,它的补码就是0-a,实际上是2的n次方-a,n为类型位数。也可以得出,补码的意义就是拿补码和原码相加会得到一个溢出的0.

6.1.4 整数的范围

对于一个字节(8位)可以表示的数为:00000000~11111111

其中00000000表示十进制0,11111111~10000000表示(-1)~(-128),00000001~01111111表示1~127 

回到数据类型,只有char类型下的11111111表示-1,因为只有一个字节,char类型数据范围为-128~127.如果想要单纯的表示0~255,不要补码。需要在数据类型前面加上unsigned。比如unsigned char a=255;输出a会得到255.如果只是char a=255,则输出a会得到-1.

如果是一个字面量变量想要表示自己是unsigned可以在后面加上u或U,表示自己是long可以加l或L。但unsigned的意义不止是扩大表达范围,而是为了做纯二进制数的计算,主要是为了移位

整数也是用纯二进制的方式计算的,所以会出现一些特殊的情况:整数越界

 在一个字节的计算中,-1+1=0,127+1=-128.0-1=-1,-128-1=127

 6.1.5 整数的格式化输出

整数的输入输出实际上只有两种:int类型和long long类型(unsigned是例外且这两种都可以加,因为这两种实际上没有区别,只是我们看待他们的方式不同),格式化符为:

  • int:%d   有unsigned就加u
  • long long:%ld  同上
#include<stdio.h>
int main()
{    
    char c=-1;
    int i=-1;
    printf("c=%u,i=%u\n",c,i);
    return 0;
}

 其运行结果为

这一串数字即为unsigned int可以表示的位数,按理来说c的结果不应该是这个,但是printf这个函数在传递小于int的变量类型时会将其转换为int,所以二者结果相等。

八进制和十六进制

以0开头的数字字面量为八进制,以0x开头的数字字面量为十六进制。

八进制和十六进制很适合表示二进制数据。因为四位二进制为一个十六进制位。三位二进制为一个八进制位。

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

 此时输出结果为

这个程序的内核其实是,你将一串数字定义为八进制或者十六进制,然后让计算机转换成十进制并输出。当你将格式化输出符更改之后,这些数字的意义也就随之改变了。比如

c=%o,i=%x;   %x输出小写,%X输出大写字母。

此时输出的结果就是 ,就是没有表示其进制的前缀。可以自行加上。 

6.1.6 选择整数类型 

为什么有那么多的整数类型!原因是早期的语言需要准确表示计算机内部的结构、接口等。 那今天我们学习时候如何选择整数的类型呢?

没什么特殊需要,就用int

 6.1.7 浮点类型

 数轴靠近0的部分是无效的,也就是不能无限趋近于0.inf即infinite,正负无穷,nan:无效数。

右边的有效数字意义:第七位为准确,第八位及以上就不准确了。

 %e:科学计数法,也可写为%E。

 

 输出结果为:

 会出现第二种值的原因是:在数学概念中两个数之间可以取的数是无限的,但在计算机中,数字都是离散的,所以不能取到无限个数,而给出的这个数就是30位小数情况下最接近0.49的一个数。

6.1.8 浮点数的范围与精度

 

 比如以下程序:

结果是:

 如果是整数运算:

会怎么样?答案是:不能通过编译。因为整数无法表示无穷,浮点数在设计时加入了上面三种特殊的结果。但是,浮点数的运算没有精度。有下列代码:

此处为了表明自己是float,需要在字面量后面加上f或者F。

 若c结果是2.468,则输出相等。那实际结果如何?

如果将c四舍五入到小数点后4位,其值确实是2.468,但实际上在计算机内部其值并不是准确的2.468.所以二者不相等。 

因此我们得出:两个浮点数不一定相等,f1==f2可能会失败,那么如何避免这个问题?

只要f1和f2的绝对值fabs(f1-f2)< 精度(float为1e-8,double为1e-16)

在计算过程中,如何避免浮点数带来的误差?如果是整数运算,可以用BCD码

 因此浮点数并不是纯二进制,而是编码类型

那么如何选择浮点数?

 6.1.9 字符类型

char:character的简写,它是一种整数,也是特殊类型:字符型,原因是:

 在上述代码中,分别赋值给两个char类型变量不同的1,一个是整数,一个是字符,运行结果为:

那么我们将c和d作为整数来输出,查看它们的值

结果为:

将d换为其他字符,得到的结果不同,说明每个字符对应着某一个整数。

  那么假如定义了一个字符char c,怎么输入数字‘1’给它?

 

 很显然,有两种方式,但是要取决于接受的格式,如果是接收整数的语句,就需要输入49,此时c的值才能为1.     程序如图

 输入1

结果为:作为整数,c=49,作为字符时候c为‘1’。这也印证了我们之前探讨过的,数据的类型全看你如何看待它。

所以字符‘1’的ASCII编码是49,当整数为49时代表字符‘1’。验证一下

 

证明是相等的。

混合输入整数和字符:

 第一个语句里两个格式符之间有空格 

 首先是第一个语句的试验,输入12 1

输出为

 如果输入12a(中间没空格),或者12  1(中间很多空格)

 都可以得到正确结果。

如果用第二条输入语句:

 则此处的32实际上为输入的空格。

所以第一个语句意思是:读完整数到没有空格才终止,而第二个语句则是只读到整数结束为止

字符计算:

因为字符也属于一种整数,那么理应可以做些运算。

则会输出B

用Z减去A?会得到25。也就是说字符加上一个数得到的结果还是字符。两个字符相减的结果是数字(这个数字代表了这两个字符的距离)。 因此有以下规律:

6.1.10 逃逸字符

是用来表示无法打印的控制字符和特殊字符,由一个反斜杠“\”开头,后面加上要打印的字符,两个字符合起来视作一个字符。

比如常见的在字符串中想要打印双引号的语句:

printf("\"");

 不同的终端在运行代码时候呈现的结果可能会不同。

\b的作用:相当于backspace,回退一个字符,如果紧跟输入新字符的话就会将最后的字符代替。如果没有的话就默认为无操作。(在devc终端下是这样)

\t的作用:相当于tab制表符,不代表相隔的数量,只有固定位置的区别

abc\t位置1
ab\t位置2
abc  <tab>  位置1
ab   <tab>  位置2

 \n的作用:在一般的终端shell中会将\n回车翻译为同时执行回车和换行,但是实际上回车和换行是模拟打字机的两个独立的动作。

6.1.11 类型转换

自动类型转换:当运算符两侧的类型不一致的时候,会自动转换成较大(能表达数的范围大)的类型 。char<short<int<long<long long 。int<float<double。

但是在printf中,任何小于int的类型会被自动转换为int,float会被自动转换为double。会出现我们上文提到过的情况。

 scanf是不会自动转换的,不过要输入short类型的数字需要%hd,longlong类型需要%ld。要给一个char类型输入整数,不行。只能先给一个整数类型输入整数,再把这个变量赋值给char类型变量。

强制的类型转换(通常是大转小):(类型名)值

也就是值放外面。比如:

  • (int)10.2
  • (short)32

但是此时要注意数据安全性,因为小的量不一定总能表示大的量,最简单的,double转float,因为二者精度不同,转换之后就不一定相同了。

再比如(short)32768。转换结果为: -32768

因为short类型能表示的最大整数就是32767,这个语句如果转换之后就会发生之前说过的“整数越界”。

如果是(char)32768。转换结果为:0

因为32768转为二进制就是:1后面跟15个0。依然是整数越界,表示为0.

  • 强制类型转换只是将变量计算为新类型的值,并不改变原有的变量类型和值。

因此转换后,输出原变量,仍然是原来的结果。

  • 强制类型转换的优先级要比四则运算高,因此这种情况会优先将a转换,但是不会将除号后的b也转换

 

应写为:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值