Tips1:

int 、short、long、unsigned、char、float、double、_Bool、 _Complex、_Imaginary
运算符:sizeof()
函数:scanf()
整数类型和浮点数类型的区别
如何书写整型和浮点型常数,如何声明这些类型的变量
如何使用printf()和scanf()函数读写不同类型的值

Tips2:

建立起这样一个概念:

函数的目的以及表达式都是为了值存在,每一个语句或者程序都产生了值或者发生了值的传递。

程序离不开数据。把数字、字母和文字输入计算机,就是希望它利用这 些数据完成某些任务。例如,需要计算一份利息或显示一份葡萄酒商的排序 列表。本章除了介绍如何读取数据外,还将教会读者如何操控数据。
C 语言提供两大系列的多种数据类型。本章详细介绍两大数据类型:整数类型和浮点数类型,讲解这些数据类型是什么、如何声明它们、如何以及 何时使用它们。除此之外,还将介绍常量和变量的区别。读者很快就能看到 第1个交互式程序。
本章仍从一个简单的程序开始。如果发现有不熟悉的内容,别担心,我 们稍后会详细解释。该程序的意图比较明了,请试着编译并运行程序清单 3.1中的源代码。为了节省时间,在输入源代码时可省略注释。
程序清单3.1 platinum.c程序
/* platinum.c -- your weight in platinum */
#include <stdio.h>
int main(void)
{
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);
/* 假设白金的价格是每盎司$1700     */
/* 14.5833用于把英镑常衡盎司转换为金衡盎司[1]*/
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;
}
 错误与警告
如果输入程序时打错(如,漏了一个分号),编译器会报告语法错误消息。然而,即使输入正确无误,编译器也可能给出一些警告,如“警告:从 double类型转换成float类型可能会丢失数据”。错误消息表明程序中有错,不能进行编译。而警告则表明,尽管编写的代码有效,但可能不是程序员想要的。警告并不终止编译。特殊的警告与C如何处理1700.0这样的值有关。本例不必理会这个问题,本章稍后会进一步说明。
输入该程序时,可以把1700.0改成贵金属白金当前的市价,但是不要改动14.5833,该数是1英镑的金衡盎司数(金衡盎司用于衡量贵金属,而英镑 常衡盎司用于衡量人的体重)。
注意,“enter your weight”的意思是输入你的体重,然后按下Enter或 Return键(不要键入体重后就一直等着)。按下Enter键是告知计算机,你已 完成输入数据。该程序需要你输入一个数字(如,155),而不是单词 (如,too much)。如果输入字母而不是数字,会导致程序出问题。这个问 题要用if语句来解决(详见第7章),因此请先输入数字。下面是程序的输 出示例:
Are you worth your weight in platinum?
Let's check it out.
Please enter your weight in pounds: 156
Your weight in platinum is worth $3867491.25.
You are easily worth that! If platinum prices drop,
eat more to maintain your value.
程序调整
即使用第2章介绍的方法,在程序中添加下面一行代码:
getchar();
程序的输出是否依旧在屏幕上一闪而过?本例,需要调用两次getchar() 函数:
getchar();
getchar();
getchar()函数读取下一个输入字符,因此程序会等待用户输入。在这种 情况下,键入 156 并按下Enter(或Return)键(发送一个换行符),然后 scanf()读取键入的数字,第1个getchar()读取换行符,第2个getchar()让程序暂 停,等待输入。

说明:用getchar();吸收换行符在scanf成功读入数据的情况下有效。为了满足用户五花八门不规范的输入,用while((getchar()!='\n');更好,因为其不论成功读入数据与否都能起到吸收的效果。

getchar();    //等待一个字符输入

while((getchar()!='\n'); //等待回车键‘enter’输入
3.1.1 程序中的新元素
程序清单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), 这让使用计算机更加饶有趣味。

3.2 变量与常量数据
在程序的指导下,计算机可以做许多事情,如数值计算、名字排序、执 行语言或视频命令、计算彗星轨道、准备邮件列表、拨电话号码、画画、做 决策或其他你能想到的事情。要完成这些任务,程序需要使用数据,即承载 信息的数字和字符。有些数据类型在程序使用之前已经预先设定好了,在整个程序的运行过程中没有变化,这些称为常量(constant)。其他数据类型在程序运行期间可能会改变或被赋值,这些称为变量(variable)。在示例程序中,weight 是一个变量,14.5833 是一个常量。那么,1700.0 是常量还 是变量?在现实生活中,白金的价格不会是常量,但是在程序中,像1700.0 这样的价格被视为常量

3.3 数据:数据类型关键字
不仅变量和常量不同,不同的数据类型之间也有差异。一些数据类型表 示数字,一些数据类型表示字母(更普遍地说是字符)。C通过识别一些基 本的数据类型来区分和使用这些不同的数据类型。如果数据是常量,编译器 一般通过用户书写的形式来识别类型(如,42是整数,42.100是浮点数)。 但是,对变量而言,要在声明时指定其类型。稍后会详细介绍如何声明变 量。现在,我们先来了解一下 C语言的基本类型关键字。K&C给出了7个与 类型相关的关键字。C90标准添加了2个关键字,C99标准又添加了3个关键 字(见表3.1)

在C语言中,用int关键字来表示基本的整数类型。后3个关键字(long、 short和unsigned)和C90新增的signed用于提供基本整数类型的变式,例如 unsigned short int和long long int。char关键字用于指定字母和其他字符(如, #、$、%和*)。另外,char类型也可以表示较小的整数。float、double和 long double表示带小数点的数。_Bool类型表示布尔值(true或false), _complex和_Imaginary分别表示复数和虚数

说明:对整数类型的认识从int类型开始

          char型一般表示字符类型,不用来表示较小整数,在某些编译器下会有警告,属于编程习惯

位、字节和字
位、字节和字是描述计算机数据单元或存储单元的术语。这里主要指存储单元。
最小的存储单元是位(bit),可以储存0或1(或者说,位用于设 置“开”或“关”)。虽然1位储存的信息有限,但是计算机中位的数量十分庞 大。位是计算机内存的基本构建块。
字节(byte)是常用的计算机存储单位。对于几乎所有的机器,1字节 均为8位。这是字节的标准定义,至少在衡量存储单位时是这样(但是,C 语言对此有不同的定义,请参阅本章3.4.3节)。既然1位可以表示0或1,那 么8位字节就有256(2的8次方)种可能的0、1的组合。通过二进制编码(仅 用0和1便可表示数字),便可表示0~255的整数或一组字符(第15章将详细 讨论二进制编码,如果感兴趣可以现在浏览一下该章的内容)。
字(word)是设计计算机时给定的自然存储单位。对于8位的微型计算 机(如,最初的苹果机), 1个字长只有8位。从那以后,个人计算机字长增至16位、32位,直到目前的64位。计算机的字长越大,其数据转移越快, 允许的内存访问也更多。计算机的字长表示计算机的位数。

3.4 C语言基本数据类型
本节将详细节介绍C语言的基本数据类型,包括如何声明变量、如何表示字面值常量(如,5或2.78),以及典型的用法。一些老式的C语言编译器 无法支持这里提到的所有类型,请查阅你使用的编译器文档,了解可以使用 哪些类型。
3.4.1 int类型
C语言提供了许多整数类型,为什么一种类型不够用?因为 C语言让程 序员针对不同情况选择不同的类型。特别是,C语言中的整数类型可表示不同的取值范围和正负值。一般情况使用int类型即可,但是为满足特定任务和 机器的要求,还可以选择其他类型。
int类型是有符号整型,即int类型的值必须是整数,可以是正整数、负整 数或零。其取值范围依计算机系统而异。一般而言,储存一个int要占用一个 机器字长。因此,早期的16位IBM PC兼容机使用16位来储存一个int值,其 取值范围(即int值的取值范围)是-32768~32767。目前的个人计算机一般 是32位,因此用32位储存一个int值。现在,个人计算机产业正逐步向着64位 处理器发展,自然能储存更大的整数。ISO C规定int的取值范围最小为-32768~32767。一般而言,系统用一个特殊位的值表示有符号整数的正负号。第15章将介绍常用的方法。

说明:对int声明的变量,其取值范围至少是16位

1.声明int变量
第2章中已经用int声明过基本整型变量。先写上int,然后写变量名,最 后加上一个分号。要声明多个变量,可以单独声明每个变量,也可在int后面列出多个变量名,变量名之间用逗号分隔。下面都是有效的声明:
int erns;
int hogs, cows, goats;
可以分别在4条声明中声明各变量,也可以在一条声明中声明4个变量。 两种方法的效果相同,都为4个int大小的变量赋予名称并分配内存空间。
以上声明创建了变量,但是并没有给它们提供值。变量如何获得值?前 面介绍过在程序中获取值的两种途径。第1种途径是赋值:
cows = 112;
第2种途径是,通过函数(如,scanf())获得值。接下来,我们着重介 绍第3种途径。
2.初始化变量
初始化(initialize)变量就是为变量赋一个初始值。在C语言中,初始化可以直接在声明中完成。只需在变量名后面加上赋值运算符(=)和待赋 给变量的值即可。如下所示:
int hogs = 21;
int cows = 32, goats = 14;
int dogs, cats = 94; /* 有效,但是这种格式很糟糕 */
以上示例的最后一行,只初始化了cats,并未初始化dogs。这种写法很 容易让人误认为dogs也被初始化为94,所以最好不要把初始化的变量和未初始化的变量放在同一条声明中。
简而言之,声明为变量创建和标记存储空间,并为其指定初始值(如图 3.4所示)//声明的意义

4.打印int值
可以使用printf()函数打印int类型的值。第2章中介绍过,%d指明了在一 行中打印整数的位置。%d称为转换说明,它指定了printf()应使用什么格式 来显示一个值。格式化字符串中的每个%d都与待打印变量列表中相应的int 值匹配。这个值可以是int类型的变量、int类型的常量或其他任何值为int类型的表达式。作为程序员,要确保转换说明的数量与待打印值的数量相同,编译器不会捕获这类型的错误。程序清单3.2演示了一个简单的程序,程序中初始化了一个变量,并打印该变量的值、一个常量值和一个简单表达式的值。另外,程序还演示了如果粗心犯错会导致什么结果。
程序清单3.2 print1.c程序

/* print1.c - 演示printf()的一些特性 */
#include <stdio.h>
int main(void)
{
int ten = 10;
int two = 2;
printf("Doing it right: ");
printf("%d minus %d is %d\n", ten, 2, ten - two);
printf("Doing it wrong: ");
printf("%d minus %d is %d\n", ten); // 遗漏2个参数
return 0;
}
编译并运行该程序,输出如下:
Doing it right: 10 minus 2 is 8
Doing it wrong: 10 minus 16 is 1650287143
在第一行输出中,第1个%d对应int类型变量ten;第2个%d对应int类型常 量2;第3个%d对应int类型表达式ten - two的值。在第二行输出中,第1个%d 对应ten的值,但是由于没有给后两个%d提供任何值,所以打印出的值是内 存中的任意值(读者在运行该程序时显示的这两个数值会与输出示例中的数 值不同,因为内存中储存的数据不同,而且编译器管理内存的位置也不 同)。

你可能会抱怨编译器为何不能捕获这种明显的错误,但实际上问题出在 printf()不寻常的设计。大部分函数都需要指定数目的参数,编译器会检查参 数的数目是否正确。但是,printf()函数的参数数目不定,可以有1个、2个、 3个或更多,编译器也爱莫能助。记住,使用printf()函数时,要确保转换说明的数量与待打印值的数量相等

5.八进制和十六进制
通常,C语言都假定整型常量是十进制数。然而,许多程序员很喜欢使 用八进制和十六进制数。因为8和16都是2的幂,而10却不是。显然,八进制 和十六进制记数系统在表达与计算机相关的值时很方便。例如,十进制数 65536经常出现在16位机中,用十六进制表示正好是10000。另外,十六进制 数的每一位的数恰好由4位二进制数表示。例如,十六进制数3是0011,十六 进制数5是0101。因此,十六进制数35的位组合(bit pattern)是00110101, 十六进制数53的位组合是01010011。这种对应关系使得十六进制和二进制的 转换非常方便。但是,计算机如何知道10000是十进制、十六进制还是二进制?在C语言中,用特定的前缀表示使用哪种进制。0x或0X前缀表示十六进制值,所以十进制数16表示成十六进制是0x10或0X10。与此类似,0前缀表示八进制。例如,十进制数16表示成八进制是020。
要清楚,使用不同的进制数是为了方便,不会影响数被储存的方式。也就是说,无论把数字写成16、020或0x10,储存该数的方式都相同,因为计算机内部都以二进制进行编码。
6.显示八进制和十六进制
在C程序中,既可以使用和显示不同进制的数。不同的进制要使用不同的转换说明。以十进制显示数字,使用%d;以八进制显示数字,使用%o; 以十六进制显示数字,使用%x。另外,要显示各进制数的前缀0、0x和0X, 必须分别使用%#o、%#x、%#X。程序清单3.3演示了一个小程序。回忆一 下,在某些集成开发环境(IDE)下编写的代码中插入getchar();语句,程序
在执行完毕后不会立即关闭执行窗口。
程序清单3.3 bases.c程序
/* bases.c--以十进制、八进制、十六进制打印十进制数100 */
#include <stdio.h>
int main(void)
{
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;
}
编译并运行该程序,输出如下:
dec = 100; octal = 144; hex = 64
dec = 100; octal = 0144; hex = 0x64
该程序以3种不同记数系统显示同一个值。printf()函数做了相应的转 换。注意,如果要在八进制和十六进制值前显示0和0x前缀,要分别在转换 说明中加入#。
3.4.2 其他整数类型
初学C语言时,int类型应该能满足大多数程序的整数类型需求。尽管如此,还应了解一下整型的其他形式。当然,也可以略过本节跳至3.4.3节阅读
char类型的相关内容,以后有需要时再阅读本节。
C语言提供3个附属关键字修饰基本整数类型:short、long和unsigned。 应记住以下几点。
short int类型(或者简写为short)占用的存储空间可能比int类型少,常 用于较小数值的场合以节省空间。与int类似,short是有符号类型。
long int或long占用的存储空间可能比int多,适用于较大数值的场合。与 int类似,long是有符号类型。
long long int或long long(C99标准加入)占用的储存空间可能比long多, 适用于更大数值的场合。该类型至少占64位。与int类似,long long是有符号 类型。
unsigned int或unsigned只用于非负值的场合。这种类型与有符号类型表 示的范围不同。例如,16位unsigned int允许的取值范围是0~65535,而不 是-32768~32767。用于表示正负号的位现在用于表示另一个二进制位,所 以无符号整型可以表示更大的数。
在C90标准中,添加了unsigned long int或unsigned long和unsigned int或 unsigned short类型。C99标准又添加了unsigned long long int或unsigned long long。
在任何有符号类型前面添加关键字signed,可强调使用有符号类型的意图。例如,short、short int、signed short、signed short int都表示同一种类型。
1.声明其他整数类型
其他整数类型的声明方式与int类型相同,下面列出了一些例子。不是所 有的C编译器都能识别最后3条声明,最后一个例子所有的类型是C99标准新 增的。
long int estine;
long johns;
short int erns;
short ribs;
unsigned int s_count;
unsigned players;
unsigned long headcount;
unsigned short yesvotes;
long long ago;
2.使用多种整数类型的原因
为什么说short类型“可能”比int类型占用的空间少,long类型“可能”比int 类型占用的空间多?因为C语言只规定了short占用的存储空间不能多于int, long占用的存储空间不能少于int。这样规定是为了适应不同的机器。例如, 过去的一台运行Windows 3的机器上,int类型和short类型都占16位,long类 型占32位。后来,Windows和苹果系统都使用16位储存short类型,32位储存 int类型和long类型(使用32位可以表示的整数数值超过20亿)。现在,计算 机普遍使用64位处理器,为了储存64位的整数,才引入了long long类型。
现在,个人计算机上最常见的设置是,long long占64位,long占32位, short占16位,int占16位或32位(依计算机的自然字长而定)。原则上,这4 种类型代表4种不同的大小,但是在实际使用中,有些类型之间通常有重叠。
C 标准对基本数据类型只规定了允许的最小大小。对于 16 位机,short 和 int 的最小取值范围是[−32767,32767];对于32位机,long的最小取值范围 是[−2147483647,2147483647]。对于unsigned short和unsigned int,最小取值范 围是[0,65535];对于unsigned long,最小取值范围是[0,4294967295]。long long类型是为了支持64位的需求,最小取值范围是 [−9223372036854775807,9223372036854775807];unsigned long long的最小取 值范围是[0,18446744073709551615]。如果要开支票,这个数是一千八百亿 亿(兆)六千七百四十四万亿零七百三十七亿零九百五十五万一千六百一十 五。但是,谁会去数?
int类型那么多,应该如何选择?首先,考虑unsigned类型。这种类型的 数常用于计数,因为计数不用负数。而且,unsigned类型可以表示更大的正数。//首先考虑unsigned类型似乎不好

选择int类型的方法:

long long占64位,long占32位, short占16位,int占16位或32位,从节省空间的角度依次选择

short  (16位)的最小取值范围是[−32767,32767],unsigned short取值范围0~65536;

long(32位)的最小取值范围 是[−2147483647,2147483647]//-21亿多到21亿多;

int的取值范围由计算机确定是16位还是32位
如果一个数超出了int类型的取值范围,且在long类型的取值范围内时, 使用long类型。然而,对于那些long占用的空间比int大的系统,使用long类 型会减慢运算速度。因此,如非必要,请不要使用long类型。另外要注意一 点:如果在long类型和int类型占用空间相同的机器上编写代码,当确实需要 32位的整数时,应使用long类型而不是int类型,以便把程序移植到16位机后 仍然可以正常工作。类似地,如果确实需要64位的整数,应使用long long类 型。
如果在int设置为32位的系统中要使用16位的值,应使用short类型以节省存储空间。通常,只有当程序使用相对于系统可用内存较大的整型数组时, 才需要重点考虑节省空间的问题。使用short类型的另一个原因是,计算机中 某些组件使用的硬件寄存器是16位。
3.long常量和long long常量
通常,程序代码中使用的数字(如,2345)都被储存为int类型。如果使 用1000000这样的大数字,超出了int类型能表示的范围,编译器会将其视为 long int类型(假设这种类型可以表示该数字)。如果数字超出long可表示的 最大值,编译器则将其视为unsigned long类型。如果还不够大,编译器则将 其视为long long或unsigned long long类型(前提是编译器能识别这些类型)。
八进制和十六进制常量被视为int类型。如果值太大,编译器会尝试使用 unsigned int。如果还不够大,编译器会依次使用long、unsigned long、longlong和unsigned long long类型。
有些情况下,需要编译器以long类型储存一个小数字。例如,编程时要 显式使用IBM PC上的内存地址时。另外,一些C标准函数也要求使用long类 型的值。要把一个较小的常量作为long类型对待,可以在值的末尾加上l(小写的L)或L后缀。使用L后缀更好,因为l看上去和数字1很像。因此,在int 为16位、long为32位的系统中,会把7作为16位储存,把7L作为32位储存。l 或L后缀也可用于八进制和十六进制整数,如020L和0x10L。
类似地,在支持long long类型的系统中,也可以使用ll或LL后缀来表示 long long类型的值,如3LL。另外,u或U后缀表示unsigned long long,如 5ull、10LLU、6LLU或9Ull。
整数溢出
如果整数超出了相应类型的取值范围会怎样?下面分别将有符号类型和无符号类型的整数设置为比最大值略大,看看会发生什么(printf()函数使 用%u说明显示unsigned int类型的值)。
/* toobig.c-- 超出系统允许的最大int值*/
#include <stdio.h>
int main(void)
{
int i = 2147483647;
unsigned int j = 4294967295;
printf("%d %d %d\n", i, i+1, i+2);
printf("%u %u %u\n", j, j+1, j+2);
return 0;
}
在我们的系统下输出的结果是:
2147483647   -2147483648  -2147483647
4294967295   0   1
可以把无符号整数j看作是汽车的里程表。当达到它能表示的最大值时,会重新从起始点开始。整数 i 也是类似的情况。它们主要的区别是,在 超过最大值时,unsigned int 类型的变量 j 从 0开始;而int类型的变量i则从 −2147483648开始。注意,当i超出(溢出)其相应类型所能表示的最大值 时,系统并未通知用户。因此,在编程时必须自己注意这类问题。
溢出行为是未定义的行为,C 标准并未定义有符号类型的溢出规则。以上描述的溢出行为比较有代表性,但是也可能会出现其他情况

4.打印short、long、long long和unsigned类型
打印unsigned int类型的值,使用%u转换说明打印long类型的值,使用%ld转换说明。如果系统中int和long的大小相同,使用%d就行。但是,这样的程序被移植到其他系统(int和long类型的大小不同)中会无法正常工 作。在x和o前面可以使用l前缀,%lx表示以十六进制格式打印long类型整 数,%lo表示以八进制格式打印long类型整数。注意,虽然C允许使用大写或 小写的常量后缀,但是在转换说明中只能用小写。
C语言有多种printf()格式。对于short类型,可以使用h前缀。%hd表示以 十进制显示short类型的整数,%ho表示以八进制显示short类型的整数。h和l 前缀都可以和u一起使用,用于表示无符号类型。例如,%lu表示打印 unsigned long类型的值。程序清单3.4演示了一些例子。对于支持long long类 型的系统,%lld和%llu分别表示有符号和无符号类型

小结:整型数据的打印--基本类型的打印,以%d和%u为转换说明(十进制);

          在此基础上,short型数据,加前缀‘h’;long型数据,加前缀‘L’;long long型加前缀‘LL’;

           如果打印八进制数据,改为‘%o’;打印十六进制数据,改为‘%x’;

3.4.3 使用字符:char类型
char类型用于储存字符(如,字母或标点符号),但是从技术层面看, char是整数类型。因为char类型实际上储存的是整数而不是字符。计算机使 用数字编码来处理字符,即用特定的整数表示特定的字符。美国最常用的编 码是ASCII编码,本书也使用此编码。例如,在ASCII码中,整数65代表大写 字母A。因此,储存字母A实际上储存的是整数65(许多IBM的大型主机使 用另一种编码——EBCDIC,其原理相同。另外,其他国家的计算机系统可 能使用完全不同的编码)。
标准ASCII码的范围是0~127,只需7位二进制数即可表示。通常,char 类型被定义为8位的存储单元,因此容纳标准ASCII码绰绰有余。许多其他系 统(如IMB PC和苹果Macs)还提供扩展ASCII码,也在8位的表示范围之 内。一般而言,C语言会保证char类型足够大,以储存系统(实现C语言的系 统)的基本字符集。
许多字符集都超过了127,甚至多于255。例如,日本汉字(kanji)字符 集。商用的统一码(Unicode)创建了一个能表示世界范围内多种字符集的 系统,目前包含的字符已超过110000个。国际标准化组织(ISO)和国际电 工技术委员会(IEC)为字符集开发了ISO/IEC 10646标准。统一码标准也与 ISO/IEC 10646标准兼容。
C语言把1字节定义为char类型占用的位(bit)数,因此无论是16位还是 32位系统,都可以使用char类型。
1.声明char类型变量
char类型变量的声明方式与其他类型变量的声明方式相同。下面是一些 例子:
char response;
char itable, latan;
以上声明创建了3个char类型的变量:response、itable和latan。
2.字符常量和初始化
如果要把一个字符常量初始化为字母 A,不必背下 ASCII 码,用计算机语言很容易做到。通过以下初始化把字母A赋给grade即可:
char grade = 'A';    //常规字符初始化方法,出于编程习惯,char声明的变量都是字符型
在C语言中,用单引号括起来的单个字符被称为字符常量(character constant)。编译器一发现'A',就会将其转换成相应的代码值。单引号必不 可少。下面还有一些其他的例子:
char broiled;   /* 声明一个char类型的变量 */
broiled = 'T';  /* 为其赋值,正确 */
broiled = T;   /* 错误!此时T是一个变量 */
broiled = "T";  /* 错误!此时"T"是一个字符串 */
如上所示,如果省略单引号,编译器认为T是一个变量名;如果把T用 双引号括起来,编译器则认为"T"是一个字符串。
实际上,字符是以数值形式储存的,所以也可使用数字代码值来赋值:
char grade = 65; /* 对于ASCII,这样做没问题,但这是一种不好的编程 风格 */
在本例中,虽然65是int类型,但是它在char类型能表示的范围内,所以 将其赋值给grade没问题。由于65是字母A对应的ASCII码,因此本例是把A 赋给grade。注意,能这样做的前提是系统使用ASCII码。其实,用'A'代替65 才是较为妥当的做法,这样在任何系统中都不会出问题。因此,最好使用字 符常量,而不是数字代码值。
奇怪的是,C语言将字符常量视为int类型而非char类型。例如,在int为
32位、char为8位的ASCII系统中,有下面的代码:
char grade = 'B';
本来'B'对应的数值66储存在32位的存储单元中,现在却可以储存在8位 的存储单元中(grade)。利用字符常量的这种特性,可以定义一个字符常 量'FATE',即把4个独立的8位ASCII码储存在一个32位存储单元中。如果把 这样的字符常量赋给char类型变量grade,只有最后8位有效。因此,grade的 值是'E'。
3.非打印字符

注:非打印字符的意义都是通过打印来实现的
单引号只适用于字符、数字和标点符号,浏览ASCII表会发现,有些 ASCII字符打印不出来。例如,一些代表行为的字符(如,退格、换行、终 端响铃或蜂鸣)。C语言提供了3种方法表示这些字符。
第1种方法前面介绍过——使用ASCII码。例如,蜂鸣字符的ASCII值是 7,因此可以这样写:
char beep = 7;
第 2 种方法是,使用特殊的符号序列表示一些特殊的字符。这些符号序列叫作转义序列(escape sequence)。表3.2列出了转义序列及其含义。


把转义序列赋给字符变量时,必须用单引号把转义序列括起来。例如, 假设有下面一行代码:
char nerf = '\n';
稍后打印变量nerf的效果是,在打印机或屏幕上另起一行。
现在,我们来仔细分析一下转义序列。使用C90新增的警报字符(\a) 是否能产生听到或看到的警报,取决于计算机的硬件,蜂鸣是最常见的警报 (在一些系统中,警报字符不起作用)。C标准规定警报字符不得改变活跃 位置。标准中的活跃位置(active position)指的是显示设备(屏幕、电传打 字机、打印机等)中下一个字符将出现的位置。简而言之,平时常说的屏幕 光标位置就是活跃位置。在程序中把警报字符输出在屏幕上的效果是,发出 一声蜂鸣,但不会移动屏幕光标。
接下来的转义字符\b、\f、\n、\r、\t和\v是常用的输出设备控制字符。了 解它们最好的方式是查看它们对活跃位置的影响。换页符(\f)把活跃位置 移至下一页的开始处;换行符(\n)把活跃位置移至下一行的开始处;回车 符(\r)把活跃位置移动到当前行的开始处;水平制表符(\t)将活跃位置 移至下一个水平制表点(通常是第1个、第9个、第17个、第25个等字符位 置);垂直制表符(\v)把活跃位置移至下一个垂直制表点。
这些转义序列字符不一定在所有的显示设备上都起作用。例如,换页符 和垂直制表符在PC屏幕上会生成奇怪的符号,光标并不会移动。只有将其 输出到打印机上时才会产生前面描述的效果。
接下来的3个转义序列(\\、\'、\")用于打印\、'、"字符(由于这些字符用于定义字符常量,是printf()函数的一部分,若直接使用它们会造成混 乱)。如果打印下面一行内容:
Gramps sez, "a \ is a backslash."
应这样编写代码:
printf("Gramps sez, \"a \\ is a backslash.\"\n");
表3.2中的最后两个转义序列(\0oo和\xhh)是ASCII码的特殊表示。如 果要用八进制ASCII码表示一个字符,可以在编码值前面加一个反斜杠(\) 并用单引号括起来。例如,如果编译器不识别警报字符(\a),可以使用 ASCII码来代替:
beep = '\007';
可以省略前面的 0,'\07'甚至'\7'都可以。即使没有前缀 0,编译器在处 理这种写法时,仍会解释为八进制。
从C90开始,不仅可以用十进制、八进制形式表示字符常量,C语言还 提供了第3种选择——用十六进制形式表示字符常量,即反斜杠后面跟一个x 或X,再加上1~3位十六进制数字。例如,Ctrl+P字符的ASCII十六进制码是 10(相当于十进制的16),可表示为'\x10'或'\x010'。图3.5列出了一些整数类 型的不同进制形式。
图3.5 int系列类型的常量写法示例
使用ASCII码时,注意数字和数字字符的区别。例如,字符4对应的 ASCII码是52。'4'表示字符4,而不是数值4。
关于转义序列,读者可能有下面3个问题。
上面最后一个例子(printf("Gramps sez, \"a \\ is a backslash\"\"n"),为何 没有用单引号把转义序列括起来?无论是普通字符还是转义序列,只要是双引号括起来的字符集合,就无需用单引号括起来。双引号中的字符集合叫作 字符串(详见第4章)。注意,该例中的其他字符(G、r、a、m、p、s等) 都没有用单引号括起来。与此类似,printf("Hello!\007\n");将打印Hello!并发出一声蜂鸣,而 printf("Hello!7\n");则打印 Hello!7。不是转义序列中的数字将作为普通字符被打印出来。
何时使用ASCII码?何时使用转义序列?如果要在转义序列(假设使 用'\f')和ASCII码('\014')之间选择,请选择前者(即'\f')。这样的写法不仅更好记,而且可移植性更高。'\f'在不使用ASCII码的系统中,仍然有效。

说明:转义序列的使用皆以转义序列打印,不使用ASCII码
如果要使用ASCII码,为何要写成'\032'而不是032?首先,'\032'能更清晰地表达程序员使用字符编码的意图。其次,类似\032这样的转义序列可以 嵌入C的字符串中,如printf("Hello!\007\n");中就嵌入了\007。
4.打印字符
printf()函数用%c指明待打印的字符。前面介绍过,一个字符变量实际上被储存为1字节的整数值。因此,如果用%d转换说明打印 char类型变量的值,打印的是一个整数。而%c转换说明告诉printf()打印该整数值对应的字符。程序清单3.5演示了打印char类型变量的两种方式。
程序清单3.5 charcode.c程序
/* charcode.c-显示字符的代码编号 */
#include <stdio.h>
int main(void)
{
char ch;
printf("Please enter a character.\n");
scanf("%c", &ch); /* 用户输入字符 */
printf("The code for %c is %d.\n", ch, ch);
return 0;
}
运行该程序后,输出示例如下:
Please enter a character.

C
The code for C is 67.       //这个程序可以看一看
运行该程序时,在输入字母后不要忘记按下Enter或Return键。随后, scanf()函数会读取用户输入的字符,&符号表示把输入的字符赋给变量ch。 接着,printf()函数打印ch的值两次,第1次打印一个字符(对应代码中 的%c),第2次打印一个十进制整数值(对应代码中的%d)。注意,printf() 函数中的转换说明决定了数据的显示方式,而不是数据的储存方式(见图 3.6)。

5.有符号还是无符号
有些C编译器把char实现为有符号类型,这意味着char可表示的范围 是-128~127。而有些C编译器把char实现为无符号类型,那么char可表示的 范围是0~255。请查阅相应的编译器手册,确定正在使用的编译器如何实现 char类型。或者,可以查阅limits.h头文件。下一章将详细介绍头文件的内容。
根据C90标准,C语言允许在关键字char前面使用signed或unsigned。这样,无论编译器默认char是什么类型,signed char表示有符号类型,而 unsigned char表示无符号类型。这在用char类型处理小整数时很有用。如果 只用char处理字符,那么char前面无需使用任何修饰符。

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

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

3.4.6 float、double和long double
各种整数类型对大多数软件开发项目而言够用了。然而,面向金融和数学的程序经常使用浮点数。C语言中的浮点类型有float、double和long double 类型。它们与FORTRAN和Pascal中的real类型一致。前面提到过,浮点类型 能表示包括小数在内更大范围的数。浮点数的表示类似于科学记数法(即用小数乘以10的幂来表示数字)。该记数系统常用于表示非常大或非常小的数。


表3.3 记数法示例
第1列是一般记数法;第2列是科学记数法;第3列是指数记数法(或称 为e记数法),这是科学记数法在计算机中的写法,e后面的数字代表10的指数。图3.7演示了更多的浮点数写法。
C标准规定,float类型必须至少能表示6位有效数字,且取值范围至少是 10-37~10+37。前一项规定指float类型必须至少精确表示小数点后的6位有效数字,如33.333333。后一项规定用于方便地表示诸如太阳质量(2.0e30千 克)、一个质子的电荷量(1.6e-19库仑)或国家债务之类的数字。通常, 系统储存一个浮点数要占用32位。其中8位用于表示指数的值和符号,剩下 24位用于表示非指数部分(也叫作尾数或有效数)及其符号。
C语言提供的另一种浮点类型是double(意为双精度)。double类型和 float类型的最小取值范围相同,但至少必须能表示10位有效数字。一般情况下,double占用64位而不是32位。一些系统将多出的 32 位全部用来表示非指数部分,这不仅增加了有效数字的位数(即提高了精度),而且还减少了舍入误差。另一些系统把其中的一些位分配给指数部分,以容纳更大的指数,从而增加了可表示数的范围。无论哪种方法,double类型的值至少有13 位有效数字,超过了标准的最低位数规定。
C语言的第3种浮点类型是long double,以满足比double类型更高的精度要求。不过,C只保证long double类型至少与double类型的精度相同。

1.声明浮点型变量
浮点型变量的声明和初始化方式与整型变量相同,下面是一些例子:
float noah, jonah;
double trouble;
float planck = 6.63e-34;
long double gnp;
2.浮点型常量
在代码中,可以用多种形式书写浮点型常量。浮点型常量的基本形式是:有符号的数字(包括小数点),后面紧跟e或E,最后是一个有符号数表示10的指数。下面是两个有效的浮点型常量:
-1.56E+12
2.87e-3
正号可以省略。可以没有小数点(如,2E5)或指数部分(如, 19.28),但是不能同时省略两者。可以省略小数部分(如,3.E16)或整数 部分(如,.45E-6),但是不能同时省略两者。下面是更多的有效浮点型常 量示例:
3.14159
.2
4e16
.8E-5
100.
不要在浮点型常量中间加空格:1.56 E+12(错误!)
默认情况下,编译器假定浮点型常量是double类型的精度。例如,假设 some是float类型的变量,编写下面的语句:
some = 4.0 * 2.0;
通常,4.0和2.0被储存为64位的double类型,使用双精度进行乘法运算,然后将乘积截断成float类型的宽度。这样做虽然计算精度更高,但是会减慢程序的运行速度。
在浮点数后面加上f或F后缀可覆盖默认设置,编译器会将浮点型常量看作float类型,如2.3f和9.11E9F。使用l或L后缀使得数字成为long double类 型,如54.3l和4.32L。注意,建议使用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是210或1024。0xa.1fp10表示的值是(10 + 1/16 + 15/256)×1024(即,十进制10364.0)。
注意,并非所有的编译器都支持C99的这一特性。
3.打印浮点值
printf()函数使用%f转换说明打印十进制记数法的float和double类型浮点数,用%e打印指数记数法的浮点数。如果系统支持十六进制格式的浮点数,可用a和A分别代替e和E。打印long double类型要使用%Lf、%Le或%La 转换说明。给那些未在函数原型中显式说明参数类型的函数(如,printf())传递参数时,C编译器会把float类型的值自动转换成double类型。

说明:浮点数输入推荐用3.0e-5f的型式;打印推荐用%e的型式;

3.4.7 复数和虚数类型
许多科学和工程计算都要用到复数和虚数。C99 标准支持复数类型和虚 数类型,但是有所保留。一些独立实现,如嵌入式处理器的实现,就不需要 使用复数和虚数(VCR芯片就不需要复数)。一般而言,虚数类型都是可选 项。C11标准把整个复数软件包都作为可选项。
简而言之,C语言有3种复数类型:float_Complex、double_Complex和 long double _Complex。例如,float _Complex类型的变量应包含两个float类型 的值,分别表示复数的实部和虚部。类似地, C语言的3种虚数类型是float _Imaginary、double _Imaginary和long double _Imaginary。
如果包含complex.h头文件,便可用complex代替_Complex,用imaginary 代替_Imaginary,还可以用I代替-1的平方根。
为何 C 标准不直接用 complex 作为关键字来代替_Complex,而要添加 一个头文件(该头文件中把complex定义为_Complex)?因为标准委员会考 虑到,如果使用新的关键字,会导致以该关键字作为标识符的现有代码全部 失效。例如,之前的 C99,许多程序员已经使用 struct complex 定义一个结 构来表示复数或者心理学程序中的心理状况(关键字struct用于定义能储存 多个值的结构,详见第14章)。让complex成为关键字会导致之前的这些代 码出现语法错误。但是,使用struct _Complex的人很少,特别是标准使用首 字母是下划线的标识符作为预留字以后。因此,标准委员会选定_Complex 作为关键字,在不用考虑名称冲突的情况下可选择使用complex

3.4.8 其他类型
现在已经介绍完C语言的所有基本数据类型。有些人认为这些类型实在 太多了,但有些人觉得还不够用。注意,虽然C语言没有字符串类型,但也 能很好地处理字符串。
C语言还有一些从基本类型衍生的其他类型,包括数组、指针、结构和 联合。尽管后面章节中会详细介绍这些类型,但是本章的程序示例中已经用到了指针〔指针(pointer)指向变量或其他数据对象位置。例如,在 scanf()函数中用到的前缀&,便创建了一个指针,告诉 scanf()把数据放在何处

3.4.9 类型大小
如何知道当前系统的指定类型的大小是多少?运行程序清单3.8,会列出当前系统的各类型的大小。
程序清单3.8 typesize.c程序      //测试当前系统各个类型的大小
//* typesize.c -- 打印类型大小 */
#include <stdio.h>
int main(void)

{
/* C99为类型大小提供%zd转换说明 */
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;
}
sizeof是C语言的内置运算符,以字节为单位给出指定类型的大小。C99 和C11提供%zd转换说明匹配sizeof的返回类型[2]。一些不支持C99和C11的 编译器可用%u或%lu代替%zd。
该程序的输出如下:
Type int has a size of 4 bytes.
Type char has a size of 1 bytes.
Type long has a size of 8 bytes.
155
Type long long has a size of 8 bytes.
Type double has a size of 8 bytes.
Type long double has a size of 16 bytes.
该程序列出了6种类型的大小,你也可以把程序中的类型更换成感兴趣的其他类型。注意,因为C语言定义了char类型是1字节,所以char类型的大 小一定是1字节。而在char类型为16位、double类型为64位的系统中,sizeof 给出的double是4字节。在limits.h和float.h头文件中有类型限制的相关信息 (下一章将详细介绍这两个头文件)。
顺带一提,注意该程序最后几行 printf()语句都被分为两行,只要不在引号内部或一个单词中间断行,就可以这样写

3.5 使用数据类型
编写程序时,应注意合理选择所需的变量及其类型。通常,用int或float 类型表示数字,char类型表示字符。在使用变量之前必须先声明,并选择有意义的变量名。初始化变量应使用与变量类型匹配的常数类型。例如:
int apples = 3;    /* 正确 */
int oranges = 3.0;  /* 不好的形式 */
与Pascal相比,C在检查类型匹配方面不太严格。C编译器甚至允许二次 初始化,但在激活了较高级别警告时,会给出警告。最好不要养成这样的习 惯。
把一个类型的数值初始化给不同类型的变量时,编译器会把值转换成与变量匹配的类型,这将导致部分数据丢失。例如,下面的初始化:
int cost = 12.99;   /* 用double类型的值初始化int类型的变量 */
float pi = 3.1415926536;  /* 用double类型的值初始化float类型的变量 */
第1个声明,cost的值是12。C编译器把浮点数转换成整数时,会直接丢 弃(截断)小数部分,而不进行四舍五入。第2个声明会损失一些精度,因 为C只保证了float类型前6位的精度。编译器对这样的初始化可能给出警告。 读者在编译程序清单3.1时可能就遇到了这种警告。

说明:当声明变量用的类型与初始化值类型不匹配的时候,以声明时关键字类型为准

例如:int oranges = 3.0; 实际上得到的变量orange是等于3的int型数据
许多程序员和公司内部都有系统化的命名约定,在变量名中体现其类 型。例如,用 i_前缀表示 int类型,us_前缀表示 unsigned short 类型。这样, 一眼就能看出来 i_smart 是 int 类型的变量, us_versmart是unsigned short类型 的变量。

3.6 参数和陷阱
有必要再次提醒读者注意 printf()函数的用法。读者应该还记得,传递给函数的信息被称为参数。例如,printf("Hello, pal.")函数调用有一个参 数:"Hello,pal."。双引号中的字符序列(如,"Hello,pal.")被称为字符串 (string),第4章将详细讲解相关内容。现在,关键是要理解无论双引号中 包含多少个字符和标点符号,一个字符串就是一个参数。
与此类似,scanf("%d", &weight)函数调用有两个参数:"%d"和 &weight。C语言用逗号分隔函数中的参数。printf()和scanf()函数与一般函数 不同,它们的参数个数是可变的。例如,前面的程序示例中调用过带一个、 两个,甚至三个参数的 printf()函数。程序要知道函数的参数个数才能正常 工作。printf()和scanf()函数用第1个参数表明后续有多少个参数,即第1个字符串中的转换说明与后面的参数一一对应。例如,下面的语句有两个%d转 换说明,说明后面还有两个参数:
printf("%d cats ate %d cans of tuna\n", cats, cans);
后面的确还有两个参数:cats和cans。
程序员要负责确保转换说明的数量、类型与后面参数的数量、类型相匹 。现在,C 语言通过函数原型机制检查函数调用时参数的个数和类型是否正确。但是,该机制对printf()和scanf()不起作用,因为这两个函数的参数个数可变。如果参数在匹配上有问题,会出现什么情况?假设你编写了程序清 单 3.9中的程序。
程序清单3.9 badcount.c程序
/* badcount.c -- 参数错误的情况 */
#include <stdio.h>
int main(void)
{
int n = 4;
int m = 5;
float f = 7.0f;
float g = 8.0f;
printf("%d\n", n, m);  /* 参数太多 */
printf("%d %d %d\n", n); /* 参数太少 */
printf("%d %d\n", f, g); /* 值的类型不匹配 */
return 0;
}
XCode 4.6(OS 10.8)的输出如下:
4
4 1 -706337836
1606414344 1
Microsoft Visual Studio Express 2012(Windows 7)的输出如下:
4
4 0 0
0 1075576832
注意,用%d显示float类型的值,其值不会被转换成int类型。在不同的平台下,缺少参数或参数类型不匹配导致的结果不同。
所有编译器都能顺利编译并运行该程序,但其中大部分会给出警告。的确,有些编译器会捕获到这类问题,然而C标准对此未作要求。因此,计算机在运行时可能不会捕获这类错误。如果程序正常运行,很难觉察出来。如 果程序没有打印出期望值或打印出意想不到的值,你才会检查 printf()函数 中的参数个数和类型是否得当。

说明:C语言在调用函数时,通过函数原型检查参数个数与类型匹配情况,但不适用于printf()和scanf()这两个函数。 程序员需自行检查参数个数以及值的类型匹配情况

3.7 转义序列示例
再来看一个程序示例,该程序使用了一些特殊的转义序列。程序清单 3.10 演示了退格(\b)、水平制表符(\t)和回车(\t)的工作方式。这些概 念在计算机使用电传打字机作为输出设备时就有了,但是它们不一定能与现 代的图形接口兼容。例如,程序清单3.10在某些Macintosh的实现中就无法正 常运行。
程序清单3.10 escape.c程序
/* escape.c -- 使用转移序列 */
#include <stdio.h>
int main(void)
{
float salary;
printf("\aEnter your desired monthly salary:"); /* 1 */
printf(" $_______\b\b\b\b\b\b\b");        /* 2 */
scanf("%f", &salary);
printf("\n\t$%.2f a month is $%.2f a year.", salary,
salary * 12.0);              /* 3 */
printf("\rGee!\n");                /* 4 */
return 0;
}

3.7.1 程序运行情况
假设在系统中运行的转义序列行为与本章描述的行为一致(实际行为可 能不同。例如,XCode 4.6把\a、\b和\r显示为颠倒的问号),下面我们来分 析这个程序。
第1条printf()语句(注释中标为1)发出一声警报(因为使用了\a),然 后打印下面的内容:
Enter your desired monthly salary:
因为printf()中的字符串末尾没有\n,所以光标停留在冒号后面。
第2条printf()语句在光标处接着打印,屏幕上显示的内容是:
Enter your desired monthly salary: $_______
冒号和美元符号之间有一个空格,这是因为第2条printf()语句中的字符 串以一个空格开始。7个退格字符使得光标左移7个位置,即把光标移至7个下划线字符的前面,紧跟在美元符号后面。通常,退格不会擦除退回所经过 的字符,但有些实现是擦除的,这和本例不同。
假设键入的数据是4000.00(并按下Enter键),屏幕显示的内容应该是:
Enter your desired monthly salary: $4000.00
键入的字符替换了下划线字符。按下Enter键后,光标移至下一行的起 始处。
第3条printf()语句中的字符串以\n\t开始。换行字符使光标移至下一行起 始处。水平制表符使光标移至该行的下一个制表点,一般是第9列(但不一 定)。然后打印字符串中的其他内容。执行完该语句后,此时屏幕显示的内容应该是:
Enter your desired monthly salary: $4000.00
$4000.00 a month is $48000.00 a year.
因为这条printf()语句中没有使用换行字符,所以光标停留在最后的点号后面。
第4条printf()语句以\r开始。这使得光标回到当前行的起始处。然后打印 Gee!,接着\n使光标移至下一行的起始处。屏幕最后显示的内容应该是:
Enter your desired monthly salary: $4000.00
Gee! $4000.00 a month is $48000.00 a year.
3.7.2 刷新输出
printf()何时把输出发送到屏幕上?最初,printf()语句把输出发送到一个 叫作缓冲区(buffer)的中间存储区域,然后缓冲区中的内容再不断被发送到屏幕上。C标准明确规定了何时把缓冲区中的内容发送到屏幕:当缓冲区满、遇到换行字符或需要输入的时候(从缓冲区把数据发送到屏幕或文件被称为刷新缓冲区)。例如,前两个 printf()语句既没有填满缓冲区,也没有换行符,但是下一条 scanf()语句要求用户输入,这迫使printf()的输出被发送到屏幕上。
旧式编译器遇到scanf()也不会强行刷新缓冲区,程序会停在那里不显示任何提示内容,等待用户输入数据。在这种情况下,可以使用换行字符刷新缓冲区。代码应改为:
printf("Enter your desired monthly salary:\n");
scanf("%f", &salary);
无论接下来的输入是否能刷新缓冲区,代码都会正常运行。这将导致光标移至下一行起始处,用户无法在提示内容同一行输入数据。还有一种刷新缓冲区的方法是使用fflush()函数。

说明:printf()函数在末尾加上‘\n',除了换行美观以外,更大的作用是刷新缓冲区让其显示在屏幕上

3.8 关键概念
C语言提供了大量的数值类型,目的是为程序员提供方便。那以整数类 型为例,C认为一种整型不够,提供了有符号、无符号,以及大小不同的整型,以满足不同程序的需求
计算机中的浮点数和整数在本质上不同,其存储方式和运算过程有很大 区别。即使两个32位存储单元储存的位组合完全相同,但是一个解释为float 类型,另一个解释为long类型,这两个相同的位组合表示的值也完全不同。 例如,在PC中,假设一个位组合表示float类型的数256.0,如果将其解释为 long类型,得到的值是113246208。C语言允许编写混合数据类型的表达式, 但是会进行自动类型转换,以便在实际运算时统一使用一种类型。

说明:格式化输出printf()函数看作是一种对数据的解释,因解释不同打印出不同的数据
计算机在内存中用数值编码来表示字符。美国最常用的是ASCII码,除 此之外C也支持其他编码。字符常量是计算机系统使用的数值编码的符号表 示,它表示为单引号括起来的字符,如'A'。
3.9 本章小结
C 有多种的数据类型。基本数据类型分为两大类:整数类型和浮点数类 型。通过为类型分配的储存量以及是有符号还是无符号,区分不同的整数类型。最小的整数类型是char,因实现不同,可以是有符号的char或无符号的 char,即unsigned char或signed char。但是,通常用char类型表示小整数时才 这样显示说明。其他整数类型有short、int、long和long long类型。C规定,后面的类型不能小于前面的类型。上述都是有符号类型,但也可以使用 unsigned关键字创建相应的无符号类型:unsigned short、unsigned int、 unsigned long和unsigned long long。或者,在类型名前加上signed修饰符显式 表明该类型是有符号类型。最后,_Bool类型是一种无符号类型,可储存0或 1,分别代表false和true。
浮点类型有3种:float、double和C90新增的long double。后面的类型应大于或等于前面的类型。有些实现可选择支持复数类型和虚数类型,通过关 键字_Complex和_Imaginary与浮点类型的关键字组合(如,double _Complex 类型和float _Imaginary类型)来表示这些类型。
整数可以表示为十进制、八进制或十六进制。0前缀表示八进制数,0x 或0X前缀表示十六进制数。例如,32、040、0x20分别以十进制、八进制、 十六进制表示同一个值。l或L前缀表明该值是long类型, ll或LL前缀表明该 值是long long类型。
在C语言中,直接表示一个字符常量的方法是:把该字符用单引号括起 来,如'Q'、'8'和'$'。C语言的转义序列(如,'\n')表示某些非打印字符。另外,还可以在八进制或十六进制数前加上一个反斜杠(如,'\007'),表示 ASCII码中的一个字符。
浮点数可写成固定小数点的形式(如,9393.912)或指数形式(如, 7.38E10)。C99和C11提供了第3种指数表示法,即用十六进制数和2的幂来 表示(如,0xa.1fp10)。
printf()函数根据转换说明打印各种类型的值。转换说明最简单的形式由 一个百分号(%)和一个转换字符组成,如%d或%f。

C语言基础之3:数据与C相关推荐

  1. SQL数据库语言基础之SqlServer数据表的六大约束(主键、外键、检查、非空、唯一性、默认值约束)的创建

    文章目录 一.主键约束(primary key) 二.外键约束(foreign key) 三.检查约束(check) 四.非空约束(not null) 五.唯一性约束(unique) 六.默认值约束( ...

  2. Flux脚本语言基础使用-查询数据(InFluxDB 查询语言)

    数据库 查询 InfluxDB 查询 mysql 查询 CSV 查询 InfluxDB 使用 from() 函数和 range() 使Flux 从 InfluxDB 查询数据. from(): buc ...

  3. C语言基础——多组数据输入

    先输入数据组数n #include <stdio.h> int main() {int n,a;scanf("%d",&n);while(n--){scanf( ...

  4. 计算机编程c 语言实型数据,C语言-基础教程-C语言实型数据

    C语言-基础教程-C语言实型数据 分类:计算机等级 | 更新时间:2016-07-08| 来源:转载 2.4.1 实型常量 实型常量又称浮点常量,是一个十进制表示的符号实数.符号实数的值包括整数部分. ...

  5. c语言字符串每个字母加4,C语言基础:各字符型数据

    C语言作为当时备受好评的编程语言,一直到现在都没有退出人们的视野.java之父说过"对于每一个计算机专业人士,他们所接触的第一种编程语言就是C语言.(C语言)有着如此多的令人惊奇的地方,这也 ...

  6. R语言基础数据操作fBasics

    R语言基础数据操作&fBasics xlsx文件的导入 library(readxl) data1 <- read_excel("C:/Users/12241/Desktop/ ...

  7. 我的全栈之路-C语言基础之数据存储

    我的全栈之路-C语言基础之数据存储 我的全栈之路 2.1 计算机的计算单位 2.1.1 容量单位 2.1.2 速度单位 2.2 计算机底层为什么只能识别二进制 2.3 进制 2.3.1 进制概述 2. ...

  8. 学习大数据需要什么语言基础

    Python易学,人人都可以掌握,如果零基础入门数据开发行业的小伙伴,可以从Python语言入手. Python语言简单易懂,适合零基础入门,在编程语言排名上升最快,能完成数据挖掘.机器学习.实时计算 ...

  9. C语言基础:结构和其他数据形式

    5# C语言基础:结构和其他数据形式 文章目录 Tips1:<img src="https://dl4.weshineapp.com/gif/20170410/5e0f6e9365be ...

  10. r语言 断轴 画图_R语言基础画图/绘图/作图

    R语言基础画图 R语言免费且开源,其强大和自由的画图功能,深受广大学生和可视化工作人员喜爱,这篇文章对如何使用R语言作基本的图形,如直方图,点图,饼状图以及箱线图进行简单介绍. 0 结构 每种图形构成 ...

最新文章

  1. Python基础编程——字典的创建
  2. vue入门总结(3)
  3. JavaScript一步一步:JavaScript 对象和HTML DOM 对象
  4. 2022-2028年中国医疗器械行业战略运营模式与典型案例分析报告
  5. SSM中实现分页与JUnit单元测试
  6. 一步步用zTree(2)
  7. GridView控件RowDataBound事件中获取列字段值的几种途径
  8. android关机背景,鍵盤消失后的Android白色背景
  9. 少说话多写代码之Python学习009——字典的创建
  10. html余下的高度,html – 使第二行的弹性项目占据容器的剩余高度
  11. 设计模式大作业绘图系统【六种设计模式+文档】
  12. 期货开户公司受到证监会的监管
  13. [http]http转义和加解密方法
  14. 揭秘微信对方正在输入……到底表示什么意思?
  15. SSO - 单点登录
  16. 使用纯CSS实现未知尺寸的图片(但高宽都小于500px)在500px的正方形容器中水平和垂直居中。你有几种方法?
  17. AnyConnect 安卓系统的使用教程
  18. cp2k 编译安装教程
  19. 知乎搜索关键字爬取相关图片
  20. css一些不常见但很有用的属性操作

热门文章

  1. 【unity 保卫星城】--- 开发笔记06(散弹 武器)
  2. 【每日最爱一句】2013.07.18
  3. 怎么知道是否已经被好友删了微信?
  4. git获取所有branch_获取Git仓库的所有分支名字
  5. 一.pandas的导入读取
  6. 什么是异地双活及应用场景
  7. Elastic App Search:免费的产品,可提供出色的搜索体验
  8. mysql查询最近7天的数据,没有数据自动补0
  9. RK3328安装liunx(ubuntu16.04)RK固件
  10. Python Couldn‘t find any class folder