![](https://cdn.jsdelivr.net/gh/ciraos/ciraos-static@main/img/erciyuan/genshin12.avif)
CPrimerPlus-第三章-数据和C[持续更新中]
葱苓Ciraos程序离不开数据。把数字、字母和文字输入计算机,就是希望它利用这些数据完成某些任务。例如,需要计算一份利息或显示一份葡萄酒商的排序列表。本章除了介绍如何读取数据外,还将教会读者如何操控数据。
C语言提供两大系列的多种数据类型。本章详细介绍两大数据类型:整数类型和浮点数类型,讲解这些数据类型是什么、如何声明它们、如何以及何时使用它们。除此之外,还将介绍常量和变量的区别。读者很快就能看到第1个交互式程序。
示例程序
1 | /*platinum.c -- your weight in platinum */ |
提示 错误与警告
如果输入程序时打错(如,漏了一个分号),编译器会报告语法错误消息。然而,即使输入正确无误,编译器也可能给出一些警告,如警告:从 double 类型转换成 float 类型可能会丢失数据
。错误消息表明程序中有错,不能进行编译。而警告则表明,尽管编写的代码有效,但可能不是程序员想要的。警告并不终止编译。特殊的警告与℃如何处理1700.0这样的值有关。本例不必理会这个问题,本章稍后会进一步说明。
输入该程序时,可以把1700.0改成贵金属白金当前的市价,但是不要改动14.5833,该数是1英镑的金衡盎司数(金衡盎司用于衡量贵金属,而英镑常衡盎司用于衡量人的体重)。
注意,“enter your weight”的意思是输入你的体重,然后按下Enter或Return键(不要键入体重后就一直等着)。按下 Enter 键是告知计算机,你已完成输入数据。该程序需要你输入一个数字(如,155),而不是单词(如,toomuch)。如果输入字母而不是数字,会导致程序出问题。这个问题要用if语句来解决(详见第7章),因此请先输入数字。下面是程序的输出示例:
1 | Are you worth your weight in platinum? |
程序调整
即使用第2章介绍的方法,在程序中添加下面一行代码:getchar();
程序的输出是否依旧在屏幕上一闪而过?本例,需要调用两次 getchar()函数:getchar();
getchar();
getchar();
函数读取下一个输入字符,因此程序会等待用户输入。在这种情况下,键入156并按下Enter(或Return)键(发送一个换行符),然后scanf()
读取键入的数字,第1个getchar()
;读取换行符,第2个getchar();
让程序暂停,等待输入。
程序中的新元素
程序清单3.1中包含C语言的一些新元素。
- 注意,代码中使用了一种新的变量声明。前面的例子中只使用了整数类型的变量(int),但是本例使用了浮点数类型(float)的变量,以便处理更大范围的数据。float类型可以储存带小数的数字。
- 程序中演示了常量的几种新写法。现在可以使用带小数点的数了。
- 为了打印新类型的变量,在
printf();
中使用%f来处理浮点值。号%.2f
中的.2用于精确控制输出,指定输出的浮点数只显示小数点后面两位。 scanf();
函数用于读取键盘的输入。$f说明scanf();
要读取用户从键盘输入的浮点数,&weight告诉scanf()把输入的值赋给名为weight的变量。scanf()函数使用&符号表明找到 weight变量的地点。下一章将详细讨论&。就目前而言,请按照这样写- 也许本程序最突出的新特点是它的交互性。计算机向用户询问信息,然后用户输入数字。与非交互式程序相比,交互式程序用起来更有趣。更重要的是,交互式使得程序更加灵活。例如,示例程序可以使用任何合理的体重,而不只是156磅。不必重写程序,就可以根据不同体重进行计算。scanf()和printf()函数用于实现这种交互。scanf()函数读取用户从键盘输入的数据,并把数据传递给程序;printf()函数读取程序中的数据,并把数据显示在屏幕上。把两个函数结合起来,就可以建立人机双向通信(见图3.1),这让使用计算机更加饶有趣味。
本章着重解释上述新特性中的前两项:各种数据类型的变量和常量。第4章将介绍后3项。
变量与常量数据
在程序的指导下,计算机可以做许多事情,如数值计算、名字排序、执行语言或视频命令、计算彗星轨道、准备邮件列表、拨电话号码、画画、做决策或其他你能想到的事情。要完成这些任务,程序需要使用数据,即承载信息的数字和字符。有些数据类型在程序使用之前已经预先设定好了,在整个程序的运行过程中没有变化,这些称为常量(constan)。其他数据类型在程序运行期间可能会改变或被赋值,这些称为变量(variable)。在示例程序中,weight是一个变量,14.5833是一个常量。那么,1700.0是常量还是变量?在现实生活中,白金的价格不会是常量,但是在程序中,像1700.0这样的价格被视为常量。
数据:数据类型关键字
不仅变量和常量不同,不同的数据类型之间也有差异。一些数据类型表示数字,·些数据类型表示字母(更普遍地说是字符)。C通过识别一些基本的数据类型来区分和使用这些不同的数据类型。如果数据是常量,编译器一般通过用户书写的形式来识别类型(如,42是整数,42.100是浮点数)。但是,对变量而言要在声明时指定其类型。稍后会详细介绍如何声明变量。现在,我们先来了解一下C语言的基本类型关键字。K&C给出了7个与类型相关的关键字。C90标准添加了2个关键字,C99 标准又添加了3个关键字(见表 3.1)。
表 3.1 C语言的数据类型关键字
最初 K&R 给出的关键字 | C90标准添加的关键字 | C99标准添加的关键字 |
---|---|---|
int | signed | _Bool |
long | void | _Complex |
short | _Imaginary | |
unsigned | ||
char | ||
float | ||
double |
在C语言中,用int 关键字来表示基本的整数类型。后3个关键字(1ong、short 和unsigned)和C90新增的signed
用于提供基本整数类型的变式,例如unsigned short int
和long long int
。char
关键字用于指定字母和其他字符(如,#、$、和*)。另外,char
类型也可以表示较小的整数。float、double 和 long double表示带小数点的数。 Bool类型表示布尔值(true或false),complex 和Imaginary 分别表示复数和虚数。
通过这些关键字创建的类型,按计算机的储存方式可分为两大基本类型:整数类型和浮点数类型。
位、字节和字
位、字节和字是描述计算机数据单元或存储单元的术语。这里主要指存储单元。最小的存储单元是位(bit ),可以储存0或|(或者说,位用于设置“开”或“关”)。虽然1位储存的信息有限,但是计算机中位的数量十分庞大。位是计算机内存的基本构建块。
字节(bvie)是常用的计算机存储单位。对于几乎所有的机器,1字节均为8位。这是字节的标准定义,至少在衡量存储单位时是这样(但是,℃语言对此有不同的定义,请参阅本章 3.4.3 节)。既然1位可以表示0或1,那么8位字节就有 256(2的8次方)种可能的0、1的组合。通过二进制编码(仅用0和】便可表示数字),便可表示 0~255 的整数或一组字符(第 15 章将详细讨论二进制编码,如果感兴趣可以现在浏览一下该章的内容)。
字(word)是设计计算机时给定的自然存储单位。对于8位的微型计算机(如,最初的苹果机),1个字长只有8位。从那以后,个人计算机字长增至 16位、32 位,直到目前的64位。计算机的字长越大,其数据转移越快,允许的内存访问也更多。
整数和浮点数
整数类型?浮点数类型?如果觉得这些术语非常陌生,别担心,下面先简述它们的含义。如果不熟悉位、字节和字的概念,请阅读上面方框中的内容。刚开始学习时,不必了解所有的细节,就像学习开车之前不必详细了解汽车内部引擎的原理一样。但是,了解一些计算机或汽车引擎内部的原理会对你有所帮助。对我们而言,整数和浮点数的区别是它们的书写方式不同。对计算机而言,它们的区别是储存方式不同。下面详细介绍整数和浮点数。
整数
和数学的概念一样,在C语言中,整数是没有小数部分的数。例如,2、-23和 2456 都是整数。而 3.14、0.22和 2.000都不是整数。计算机以二进制数字储存整数,例如,整数7以二进制写是111。因此,要在8位字节中储存该数字,需要把前5位都设置成0,后3位设置成1(如图3.2所示)。
浮点数
浮点数与数学中实数的概念差不多。2.75、3.16E7、7.00和2e-8都是浮点数。注意,在一个值后面加上一个小数点,该值就成为一个浮点值。所以,7是整数,7.00是浮点数。显然,书写浮点数有多种形式。稍后将详细介绍e记数法,这里先做简要介绍:3.16E7表示3.16X10(3.16乘以10的7次方)。其中,107=10000000,7被称为10的指数。
这里关键要理解浮点数和整数的储存方案不同。计算机把浮点数分成小数部分和指数部分来表示,而且分开储存这两部分。因此,虽然7.00和7在数值上相同,但是它们的储存方式不同。在十进制下,可以把 7.0写成 0.7E1。这里,0.7是小数部分,1是指数部分。图3.3演示了一个储存浮点数的例子。当然,计算机在内部使用二进制和2的幂进行储存,而不是10的幂。第15章将详述相关内容。现在,我们着重讲解这两种类型的实际区别。
- 整数没有小数部分,浮点数有小数部分。
- 浮点数可以表示的范围比整数大。参见本章末的表3.3。
- 对于一些算术运算(如,两个很大的数相减),浮点数损失的精度更多。
- 因为在任何区间内(如,10到2.0之间)都存在无穷多个实数,所以计算机的浮点数不能表示区间内所有的值。浮点数通常只是实际值的近似值。例如,7.0可能被储存为浮点值6.99999。稍后会
- 讨论更多精度方面的内容。过去,浮点运算比整数运算慢。不过,现在许多CPU都包含浮点处理器,缩小了速度上的差距。
C语言基本数据类型
本节将详细节介绍C语言的基本数据类型,包括如何声明变量、如何表示字面值常量(如,5或2.78),以及典型的用法。一些老式的C语言编译器无法支持这里提到的所有类型,请查阅你使用的编译器文档,了解可以使用哪些类型。
int 类型
C语言提供了许多整数类型,为什么一种类型不够用?因为C语言让程序员针对不同情况选择不同的类型。特别是,C语言中的整数类型可表示不同的取值范围和正负值。一般情况使用int类型即可,但是为满足特定任务和机器的要求,还可以选择其他类型。
int 类型是有符号整型,即int类型的值必须是整数,可以是正整数、负整数或零。其取值范围依计算机系统而异。一般而言,储存一个int要占用一个机器字长。因此,早期的16位IBM PC兼容机使用16位来储存一个 int值,其取值范围(即int值的取值范围)是-2768~32767
。目前的个人计算机一般是 32位,因此用32位储存一个int值。现在,个人计算机产业正逐步向着 64位处理器发展,自然能储存更大的整数。ISOC规定int的取值范围最小为-32768~32767
。一般而言,系统用一个特殊位的值表示有符号整数的正负号。第15章将介绍常用的方法。
- 声明 int 变量
第2章中已经用int声明过基本整型变量。先写上int,然后写变量名,最后加上一个分号。要声明
多个变量,可以单独声明每个变量,也可在int后面列出多个变量名,变量名之间用逗号分隔。下面都是
有效的声明:
1 | int erns; |
可以分别在4条声明中声明各变量,也可以在一条声明中声明4个变量。两种方法的效果相同,都为4
个int 大小的变量赋予名称并分配内存空间。
以上声明创建了变量,但是并没有给它们提供值。变量如何获得值?前面介绍过在程序中获取值的两
种途径。第1种途径是赋值:
- 初始化变量
初始化(iniialize)变量就是为变量赋一个初始值。在C语言中,初始化可以直接在声明中完成。只需在变量名后面加上赋值运算符(=)和待赋给变量的值即可。如下所示:
1 | int hoqs =21; |
以上示例的最后一行,只初始化了cats,并未初始化dogs。这种写法很容易让人误认为 dogs 也被
初始化为94,所以最好不要把初始化的变量和未初始化的变量放在同一条声明中。
简而言之,声明为变量创建和标记存储空间,并为其指定初始值(如图3.4所示)。
int 类型常量
上面示例中出现的整数(21、32、14和94)都是整型常量或整型字面量。C语言把不含小数点和指数的数作为整数。因此,22和-44都是整型常量,但是22.0和2.2E1则不是。C语言把大多数整型常量视为int类型,但是非常大的整数除外。详见后面“1ong 常量和 long long 常量”小节对 1ong int 类型的讨论。打印 int 值