第三章 数据与C

本章主要介绍以下内容:

关键字:int, short, long, unsigned, char, float, double, _Bool, _Complex, _Imaginary

运算符:sizeof()

函数:scanf()

整数类型和浮点数类型的区别

如何书写整数和浮点型常数,如何声明这些类型的变量

如何使用printf()和scanf()函数读写不同类型的值


目录

3.1 示例代码引入:

3.2 变量与常量数据

3.3 位、字节和字

3.4 整数和浮点数

3.4.1 整数:

3.4.2 浮点数:

3.5 C语言基本数据类型

3.5.1 int类型

3.5.2 其他整数类型:

3.5.3 char类型

3.5.3.1 字符常量和初始化

3.5.3.2 非打印字符

3.5.3.3 打印字符

3.5.4 _Bool类型

3.5.5 float, double和long double

3.5.5.1 float类型:

3.5.5.2 double类型:

3.5.5.3 long double类型:

3.6 浮点数的上溢和下溢

3.6.1 上溢:

3.6.2 下溢:

3.7 浮点数舍入错误

3.8 复数和虚数类型

3.9 类型大小


3.1 示例代码引入:

在第三章开始,又给出了一个示例代码:
 

#include<stdio.h>

int main(){
    float weight;
    float value;
    printf("Are you worth your weight in platinum?\n");
    printf("Let's check it out.\n");
    printf("Please enter your weight in pounds: ");
    scanf("%f", &weight);
    value = 1700.0 * weight * 14.5833;
    printf("Your weight in platinum is worth $%.2f.\n", value);
    printf("You are easily worth that! If platinum prices drop,\n");
    printf("eat more to maintain your value.\n");
    return 0;
}

如果我们在IDE上面运行时又出现了一闪而过的情况,需要调用两次getchar()。

getchar()函数读取下一个输入字符,因此程序会等待用户输入。在这种情况下,我们输入weight的值之后,按下enter键,scanf()会读取键入的数字,第一个getchar()读取换行符,第二个getchar()让程序暂停,等待输入。

在程序中的printf()和scanf()函数结合,建立起了人机双向通信:

3.2 变量与常量数据

常量:有些数据类型在程序使用之前已经预先设定好了,在整个程序的运行过程中没有变化

变量:其他数据类型在程序运行期间可能会改变或被赋值

数据:数据类型关键字

针对常量,编译器通过用户书写形式来识别类型。

对于变量,需要在声明时就指定其类型。

以下是C语言的数据类型关键字

按照计算机的储存方式可以将关键字分为:整数类型和浮点数类型。

3.3 位、字节和字

含义:作为描述计算机数据单元或存储单元的术语,这里主要指存储单元。

最小的存储单元是位(bit),可以存储0或1,位是计算机内存的基本构建块。

常用的计算机存储单位是字节(byte),1字节基本等于8位。

设计计算机时给定的自然存储单位是字(word),对于8位的微型计算机,1个字长只有8位,后来发展至16位、32位,到现在的64位。计算机字长越大,其数据转移越快,允许的内存访问也就更多。

3.4 整数和浮点数

对于人类而言,整数和浮点数的区别是它们的书写方式不同;

对于计算机而言,整数和浮点数的区别是储存方式不同。

3.4.1 整数:

在C语言中,整数是没有小数部分的数,计算机以二进制数字储存整数。

例如:

3.4.2 浮点数:

浮点数与数学中实数的概念差不多,2.75、3.16E7、7.00和2e-8都是浮点数。在一个数后面加上一个小数点,该值就成为一个浮点值。书写浮点值有多种形式。

浮点数表示的范围比整数大,对于一些算术运算,浮点数损失的精度更多。

计算机将浮点数分为了小数部分指数部分来表示,并且分开储存这两部分。

因为在任何区间内都存在无穷多个实数,所以计算机的浮点数不能表示区间内所有的值,浮点数只是实际值的近似值。例如,7.0可能被储存为浮点值6.999。

过去,浮点运算比整数运算慢,现在许多CPU都包含了浮点处理器,缩小了速度上的差距。

3.5 C语言基本数据类型

3.5.1 int类型

C规定int的取值范围最小为-32768~32767。

声明int变量——>初始化变量——>int类型常量——>打印int值

在进行初始化变量时,要尽量避免这种格式:
int dogs, cats = 94;

这种情况只初始化了cats,没有初始化dogs,但是这种写法容易让人误认为dogs也被初始化为94,所以不要把初始化的变量和未初始化的变量放在同一条声明中。

声明为变量创建和标记存储空间,并为其指定初始值:

八进制和十六进制

十进制:%d

八进制:%o

十六进制:%x

如果要显示各进制的前缀则必须使用%#o, %#x, %#X

如下图代码示例:
 

#include<stdio.h>

int main(){
    int x = 100;
    printf("dec = %d; octal = %o; hex = %x\n",x, x, x);
    printf("dec = %d; octal = %#o; hex = %#x\n", x, x, x);
    return 0;
}

得到运行结果:

3.5.2 其他整数类型:

short——占用存储空间比int类型少,用于较小数值的场合以节省空间,是有符号类型

long int或long——占用空间比int多,适用于较大数值的场合,是有符号类型

long long int或long long——存储空间比int多,适用于更大数值的场合,该类型至少占64位,是有符合类型

unsigned int或unsigned只用于非负值的场合,无符号整型可以表示更大的数。

C语言规定,short占用的存储空间不能多于int,long占用的存储空间不能少于int。

现在,个人计算机上最常见的设置是,long long占64位,long占32位,short占16位,int占16位或32位(依计算机的自然字长而定)

整数溢出

当数字达到能表达的最大值时,会重新从起点开始,不过无符号数和有符号数的起点不同,例如,unsigned int类型变量从0开始,int类型变量从-2147483648开始。当变量超出其相应类型所能表示的最大值时,系统并未通知用户,因此需要在编程时自己注意这些问题。

打印unsigned int类型的值,用%u转换说明;打印long类型的值,使用%ld转换说明,如果系统中int和long的大小相同,使用%d就行(这种程序移植到其他系统中可能无法正常工作,因为int和long类型的大小不同),short类型,用h前缀,例如%hd表示以十进制显示的short类型的整数。h和l前缀都可以和u一起使用。

3.5.3 char类型

char类型用于储存字符,但是从技术层面来看,char是整数类型,char实际上存储的是整数而不是字符。

计算机用特定的整数来表示特定的字符,最常用的编码是ASCII编码(例如,65代表A)

char类型被定义为8位存储单元,标准ASCII码的范围为0~127。

3.5.3.1 字符常量和初始化
char broiled;    /*声明一个char类型的变量*/
broiled = 'T';   /*为其赋值,正确*/
broiled = T;     /*错误!此时T是一个变量*/
broiled = "T";   /*错误!此时"T"是一个字符串*/

C语言将字符常量视为int类型而非char类型。

例如,在int为32位、char为8位的ASCII系统中,有下面的代码:
char grade = 'B';

'B'对应数值66储存在32位的存储单元中,现在却可以储存在8位的存储单元中(grade),利用字符常量的这种特性,可以定义一个字符常量'FATE',即把四个独立的8位ASCII码储存在一个32位存储单元中,如果把这样的字符常量赋给char类型变量grade,只有最后8位有效。因此,grade的是'E'。

3.5.3.2 非打印字符

有些ASCII字符打印不出来,例如一些行为的字符,C语言提供3种方法表示这些字符。

1. 使用ASCII码

例如蜂鸣字符的ASCII值是7,因此可以写成:char beep = 7;

2. 使用一些特殊的符号序列表示一些特殊字符(转义序列)

把转义序列赋给字符变量时,必须使用单引号把转义序列括起来,例如:char nerf = '\n';

C标准规定警报字符不得改变活跃位置。

标准中的活跃位置(active positiion)指的是显示设备(屏幕、电传打字机、打印机等)中下一个字符将出现的位置(也就是屏幕的光标位置)

3. 用十六进制表示字符常量

即反斜杠后面跟一个x或X,再加上1~3位十六进制数字。

下面列出了一些整数类型的不同进制形式:

在使用ASCII码时,要注意数字和数字字符的区别。例如,字符4对应的ASCII码是52,‘4’表示字符4,而不是数值4.

注意:printf("Gramps sez, \"a \\ is a backslash\" \" n"); 在这里并没有用单引号将转义序列括起来,无论是普通字符还是转义序列,只要是双括号括起来的字符集合,就无需用单引号括起来。双引号中的字符集合叫做字符串。

3.5.3.3 打印字符

printf()函数用%c指明待打印的字符。

如果用%d转换说明打印char类型变量的值,打印的是一个整数,%c转换说明告诉printf()打印该整数值对应的字符。

示例:
 

#include<stdio.h>

int main(){
    char ch;
    printf("Please enter a character.\n");
    scanf("%c",&ch);
    printf("The code for %c is %d.\n",ch, ch);
    return 0;
}

运行结果:

程序中的printf()函数中的转换说明决定了数据的显示方式,而不是数据的储存方式:

有些编译器将char实现为有符号类型,这意味着char可表示的范围是-128~127,而有些C编译器将char实现为无符号类型,意味着char可表示的范围是0~255。根据C90标准,C语言允许在关键字char前面使用signed或unsigned。

3.5.4 _Bool类型

用于表示布尔值,即逻辑值true和false。由于C语言用1表示true,用0表示false,所以_Bool类型实际上也是一种整数类型。但原则上它仅占用1位存储空间,因为对0和1而言,1位的存储空间足够了。

可移植类型:stdint.h和inttypes.h

C99中新增两个头文件stdint.h和inttypes.h,以保证C语言的类型在各系统中的功能相同。

stdint.h头文件中有很多新的类型名。例如,int32_t表示32位的有符号整数类型,在使用32位int的系统中,头文件会把int32_t作为int的别名。

不同的系统也可以定义相同的类型名

int为16位,long为32位的系统会把int32_t作为long的别名,然后,使用int32_t类型编写程序,并包含stdint.h头文件时,编译器会把int或long替换成与当前系统匹配的类型。

如果系统不支持精确宽度整数类型?

C99和C11提供了第2类别名集合。一些类型名保证所表示的类型一定是至少有指定宽度的最小整数类型。这组类型集合被称为最小宽度类型。(int_least8_t是可容纳8位有符号整数值的类型中宽度最小的类型的一个别名)。

一些程序员更关心速度而非空间?

C99和C11定义了一组可使计算达到最快的类型的集合,这组类型集合被称为最快最小宽度类型(int_fast8_t被定义为系统中对8位有符号值而言运算最快的整数类型的别名)

一些程序员需要系统的最大整数类型?C99定义了最大的有符号整数类型intmax_t,可储存任何有效的有符号整数值。

3.5.5 float, double和long double

浮点类型能表示包括小数在内的更大范围的数,浮点数的表示类似于科学记数法,该记数系统常用于表示非常大或非常小的数。

下面是一个记数法的示例:

3.5.5.1 float类型:

C标准规定,float类型必须能够表示至少6位有效数字,且取值范围至少是10^-37~10^+37。前一项规定指float类型必须至少精确表示小数点后的6位有效数字,后一项规定用于方便的表示诸如太阳质量、一个质子的电荷量或国家债务之类的数字。

通常,系统储存一个浮点数要占用32位,其中8位用于表示指数的值和符号,剩下的24位用于表示非指数部分(也叫尾数或有效数)及其符号。

更多浮点数写法示例:

3.5.5.2 double类型:

double意为双精度,double类型和float类型的最小取值范围相同,但至少必须能表示10位有效数字。

一般情况下,double占用64位而不是32位,一些系统将多出的32位全部用来表示非指数部分,这不仅增加了有效数字的位数(即提高了精度),而且还减少了舍入误差。另一些系统把其中的一些位分配给指数部分,以容纳更大的指数部分,从而增加了可表示数的范围。无论哪种方法,double类型的值至少有13位有效数字,超过了标准的最低位数规定。

3.5.5.3 long double类型:

可以满足比double类型更高的精度要求。不过,C只保证long double类型至少与double类型的精度相同。

注意
默认情况下,编译器假定浮点型常量是double类型的精度。

例如,假设some是float类型的变量,编写下面的语句:
some = 4.0*2.0;     通常,4.0和2.0被储存为64位double类型,使用双精度进行乘法运算,然后将乘积截断成float类型的宽度,这样虽然精度更高,但是会减慢程序的运行速度。

在浮点数后面加上f或者F可覆盖默认设置,编译器会将浮点型常量看作float类型,使用l或L后缀使得数字成为long double类型,建议使用L后缀,因为l和1容易混淆。没有后缀的浮点型常量是double类型。

C99标准加了一种新的浮点型常量格式,用十六进制表示浮点型常量,即在十六进制数前加上十六进制前缀(0x或0X),用p或P分别代替e和E,用2的幂代替10的幂(即,p计数法)(例子:0xa.1fp10,在这个例子中,十六进制a等于十进制10,.1f是1/16加上15/256(十六进制f等于十进制15),p10是2^10或者1024, 0xa.1fp10表示的值是(10+1/15+15/256)*1024,即十进制10364.0)

printf()函数使用 %f转换说明打印十进制记数法的float和double类型浮点数,用%e打印指数记数法的浮点数。如果系统支持十六进制格式的浮点数,可用a和A分别代替e和E。打印long double类型要使用%Lf, %Le或%La转换说明。给未在函数原型中显式说明参数类型的函数传递参数时,C编译器会把float类型的值自动转换成double类型。

代码示例:
 

#include<stdio.h>

int main(){
    
    float aboat = 32000.0;
    double abet = 2.14e9;
    long double dip = 5.32e-5;
    printf("%f can be written %e\n",aboat, aboat);
    printf("And it's %a in hexadecimal, powers of 2 notation\n", aboat);
    printf("%f can be written %e\n", abet, abet);
    printf("%Lf can be written %Le\n",dip, dip);
    
    return 0;
}

运行结果:

3.6 浮点数的上溢和下溢

3.6.1 上溢:

当计算导致数字过大,超过当前类型能表达的范围时,就会发生上溢。现在C语言规定,上溢时会给该值赋一个表示无穷大的特定值,而且printf()显示该值为inf或infinity。

3.6.2 下溢:

当一个数字是float类型能够用全部精度表示的最小数字,把它除以2之后,这个操作会减少指数部分,但是假设的情况中,指数已经是最小值了,所以计算机只能把尾数部分的位向右移,空出第1个二进制位,并丢弃最后一个二进制数。这种情况叫做下溢。

C语言把损失了类型全精度的浮点值称为低于正常的值。如果除以一个非常大的值,会导致所有的位都为0,现在,C库已经提供了用于检查计算是否会产生低于正常值的函数。

还有一个特殊的浮点值NaN(not a number的缩写),例如,给asin()函数传递一个值,该函数将返回一个角度,该角度的正弦就是传入函数的值。但是正弦值不能大于1,因此,如果传入的参数大于1,该函数的行为是未定义的。在这种情况下,该函数将返回NaN值,printf()函数可将其显示为nan、NaN或其他类似的内容。

3.7 浮点数舍入错误

给定一个数,加上1,再减去原来给定的数,结果不一定为1,有可能会得到很多奇怪的答案,因为计算机缺少足够的小数位来完成正确的运算。

3.8 复数和虚数类型

C语言有3种复数类型:float_Complex、double_Complex和long double_Complex。(float_Complex类型的变量应该包含两个float类型,分别是复数的实部和虚部)

类似的,C语言也有3种虚数类型。

如果包含complex.h头文件,可用complex代替_Complex,用imaginary代替_Imaginary,还可以用I代替-1的平方根。

3.9 类型大小

利用sizeof这个内置运算符,以字节为单位给出指定类型的大小,C99和C11提供%zd转换说明匹配sizeof的返回类型,一些不支持C99和C11的编译器可用%u或%lu代替%zd。

#include<stdio.h>

int main(){
    printf("Type int has a size of %zd bytes.\n",sizeof(int));
    printf("Type char has a size of %zd bytes.\n",sizeof(char));
    printf("Type long has a size of %zd bytes.\n",sizeof(long));
    printf("Type long long has a size of %zd bytes.\n",sizeof(long long));
    printf("Type double has a size of %zd bytes.\n",sizeof(double));
    printf("Type long double has a size of %zd bytes.\n", sizeof(long double));
    return 0;
}

运行结果:

  • 35
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值