赞
踩
声明:加粗部分只是我注明了我以前忽略的部分,没有特殊含义。
本章介绍以下内容:
/* 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); 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这样的值有关。本例不必理会这个问题,本章稍后会进一步说明。
按下Enter键是告知计算机,你已完成输入数据。该程序需要你输入一个数字(如,155),而不是单词(如,too much)。如果输入字母而不是数字,会导致程序出问题。这个问题要用if语句来解决(详见第7章)
C通过识别一些基本的数据类型来区分和使用这些不同的数据类型。如果数据是常量,编译器一般通过用户书写的形式来识别类型(如,42是整数,42.100是浮点数)。
但是,对变量而言,要在声明时指定其类型。
后3个关键字(long、short和unsigned)和C90新增的signed用于提供基本整数类型的变式,例如unsigned short int和long long int。
char关键字用于指定字母和其他字符(如,#、$、%和*)。另外,char类型也可以表示较小的整数。
float、double和long double表示带小数点的数。
_Bool类型表示布尔值(true或false),_Complex和_Imaginary分别表示复数和虚数。
按计算机的存储方式可分为两大基本类型:整数类型和浮点数类型。
- 最小的存储单元是位(bit),可以存储0或1
- 字节(byte)是常用的计算机存储单位。对于几乎所有的机器,1字节均为8位。
- 字(word)是设计计算机时给定的自然存储单位。对于8位的微型计算机(如,最初的苹果机),1个字长只有8位。从那以后,个人计算机字长增至16位、32位,直到目前的64位。计算机的字长越大,其数据转移越快,允许的内存访问也更多。
int hogs = 21;
int cows = 32, goats = 14;
int dogs, cats = 94; /* 有效,但是这种格式很糟糕 */
/* 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;}
}
/* 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;
}
该程序以3种不同记数系统显示同一个值。printf()函数做了相应的转换。
C语言提供3个附属关键字修饰基本整数类型:short、long和unsigned。
/* 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
/* print2.c--更多printf()的特性 */
#include<stdio.h>
int main(void)
{
unsigned int un = 3000000000; /* int为32位和short为16位的系统 */
short end = 200;
long big = 65537;
long long verybig = 12345678908642;
printf("un = %u and not %d\n", un, un);
printf("end = %hd and %d\n", end, end);
printf("big = %ld and not %hd\n", big, big);
printf("verybig= %lld and not %ld\n", verybig, verybig);
return 0;
}
在特定的系统中输出如下(输出的结果可能不同):
un = 3000000000 and not -1294967296
end = 200 and 200
big = 65537 and not 1
verybig= 12345678908642 and not 1942899938
对于无符号变量un,使用%d会生成负值!其原因是,无符号值3000000000和有符号值−129496296在系统内存中的内部表示完全相同(详见第15章)。因此,如果告诉printf()该数是无符号数,它打印一个值;如果告诉它该数是有符号数,它将打印另一个值。
在待打印的值大于有符号值的最大值时,会发生这种情况。对于较小的正数(如96),有符号和无符号类型的存储、显示都相同。
char类型用于存储字符(如,字母或标点符号),但是从技术层面看,char是整数类型。因为char类型实际上存储的是整数而不是字符。
计算机使用数字编码来处理字符,即用特定的整数表示特定的字符。
美国最常用的编码是ASCII编码,本书也使用此编码。例如,在ASCII码中,整数65代表大写字母A。因此,存储字母A实际上存储的是整数65
char类型变量的声明方式与其他类型变量的声明方式相同。下面是一些例子:
char response;
char itable, latan;
如果要把一个字符常量初始化为字母A,不必背下ASCII码,用计算机语言很容易做到。通过以下初始化把字母A赋给grade即可:char grade = ‘A’;
在C语言中,用单引号括起来的单个字符被称为字符常量
如果省略单引号,编译器认为T是一个变量名;如果把T用双引号括起来,编译器则认为"T"是一个字符串。
单引号只适用于字符、数字和标点符号,浏览ASCII表会发现,有些ASCII字符打印不出来。例如,一些代表行为的字符(如,退格、换行、终端响铃或蜂鸣)。C语言提供了3种方法表示这些字符。
第1种方法前面介绍过——使用ASCII码。例如,蜂鸣字符的ASCII值是7,因此可以这样写:
char beep = 7;
第2种方法是,使用特殊的符号序列表示一些特殊的字符。这些符号序列叫作转义序列(escape sequence)。把转义序列赋给字符变量时,必须用单引号把转义序列括起来。例如,假设有下面一行代码:char nerf = ‘\n’;
稍后打印变量nerf的效果是,在打印机或屏幕上另起一行。
标准中的活跃位置(active position)指的是显示设备(屏幕、电传打字机、打印机等)中下一个字符将出现的位置。
- 换页符(\f)把活跃位置移至下一页的开始处;
- 换行符(\n)把活跃位置移至下一行的开始处;
- 回车符(\r)把活跃位置移动到当前行的开始处;
- 水平制表符(\t)将活跃位置移至下一个水平制表点(通常是第1个、第9个、第17个、第25个等字符位置);
- 垂直制表符(\v)把活跃位置移至下一个垂直制表点。
- 接下来的3个转义序列(\\、\’、\")用于打印\、’、"字符(由于这些字符用于定义字符常量,是printf()函数的一部分,若直接使用它们会造成混乱)。如果打印下面一行内容:
- Gramps sez, “a \ is a backslash.”
应这样编写代码:
printf(“Gramps sez, “a \ is a backslash.”\n”);
使用ASCII码时,注意数字和数字字符的区别。例如,字符4对应的ASCII码是52。'4’表示字符4,而不是数值4。
printf()函数用%c指明待打印的字符。
前面介绍过,一个字符变量实际上被存储为1字节的整数值。因此,如果用%d转换说明打印char类型变量的值,打印的是一个整数。而%c转换说明告诉printf()打印该整数值对应的字符。
/* 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.
printf()函数打印ch的值两次,第1次打印一个字符(对应代码中的%c),第2次打印一个十进制整数值(对应代码中的%d)。
C99标准添加了_Bool类型,用于表示布尔值,即逻辑值true和false。因为C语言用值1表示true,值0表示false,所以_Bool类型实际上也是一种整数类型。但原则上它仅占用1位存储空间,因为对0和1而言,1位的存储空间足够了。
/* altnames.c -- 可移植整数类型名 */
#include <stdio.h>
#include <inttypes.h> // 支持可移植类型
int main(void)
{
int32_t me32; // me32是一个32位有符号整型变量
me32 = 45933945;
printf("First, assume int32_t is int: ");
printf("me32 = %d\n", me32);
printf("Next, let's not make any assumptions.\n");
printf("Instead, use a \"macro\" from inttypes.h: ");
printf("me32 = %" PRId32 "\n", me32);
return 0;
}
篇幅有限,无法介绍扩展的所有整数类型。本节主要是为了让读者知道,在需要时可进行这种级别的类型控制。
C标准规定,float类型必须至少能表示6位有效数字,且取值范围至少是10-37~10+37。前一项规定指float类型必须能够表示33.333333的前6位数字,而不是精确到小数点后6位数字。后一项规定用于方便地表示诸如太阳质量(2.0e30千克)、一个质子的电荷量(1.6e-19库仑)或国家债务之类的数字。
通常,系统存储一个浮点数要占用32位。其中8位用于表示指数的值和符号,剩下24位用于表示非指数部分(也叫作尾数或有效数)及其符号。
double类型和float类型的最小取值范围相同,但至少必须能表示10位有效数字。
一般情况下,double占用64位而不是32位。
C语言的第3种浮点类型是long double,以满足比double类型更高的精度要求。不过,C只保证long double类型至少与double类型的精度相同。
在代码中,可以用多种形式书写浮点型常量。浮点型常量的基本形式是:有符号的数字(包括小数点),后面紧跟e或E,最后是一个有符号数表示10的指数。下面是两个有效的浮点型常量:
-1.56E
+122.87e-3
正号可以省略。可以没有小数点(如,2E5)或指数部分(如,19.28),但是不能同时省略两者。
可以省略小数部分(如,3.E16)或整数部分(如,.45E-6),但是不能同时省略两者。下面是更多的有效浮点型常量示例:
3.14159
.2
4e16
.8E-5
100.
不要在浮点型常量中间加空格:1.56 E+12(错误!)
默认情况下,编译器假定浮点型常量是double类型的精度。
some = 4.0 * 2.0;
通常,4.0和2.0被存储为64位的double类型,使用双精度进行乘法运算,然后将乘积截断成float类型的宽度。这样做虽然计算精度更高,但是会减慢程序的运行速度。
在浮点数后面加上f或F后缀可覆盖默认设置,编译器会将浮点型常量看作float类型,如2.3f和9.11E9F。
C99标准添加了一种新的浮点型常量格式——用十六进制表示浮点型常量,即在十六进制数前加上十六进制前缀(0x或0X),用p和P分别代替e和E,用2的幂代替10的幂(即,p计数法)。如下所示:
0xa.1fp10
printf()函数使用%f转换说明打印十进制记数法的float和double类型浮点数,用%e打印指数记数法的浮点数。
如果系统支持十六进制格式的浮点数,可用a和A分别代替e和E。
打印long double类型要使用%Lf、%Le或%La转换说明。
当计算导致数字过大,超过当前类型能表达的范围时,就会发生上溢。这种行为在过去是未定义的,不过现在C语言规定,在这种情况下会给toobig赋一个表示无穷大的特定值,而且printf()显示该值为inf或infinity
以十进制为例,把一个有4位有效数字的数(如,0.1234E-10)除以10,得到的结果是0.0123E-10。虽然得到了结果,但是在计算过程中却损失了原末尾有效位上的数字。这种情况叫作下溢
C语言把损失了类型全精度的浮点值称为低于正常的(subnormal)浮点值。因此,把最小的正浮点数除以2将得到一个低于正常的值。如果除以一个非常大的值,会导致所有的位都为0。现在,C库已提供了用于检查计算是否会产生低于正常值的函数。
还有另一个特殊的浮点值NaN(not a number的缩写)。例如,给asin()函数传递一个值,该函数将返回一个角度,该角度的正弦就是传入函数的值。但是正弦值不能大于1,因此,如果传入的参数大于1,该函数的行为是未定义的。在这种情况下,该函数将返回NaN值,printf()函数可将其显示为nan、NaN或其他类似的内容。
/* floaterr.c--演示舍入错误 */
#include<stdio.h>
int main(void)
{
float a, b;
b = 2.0e20 + 1.0;
a = b - 2.0e20;
printf("%f \n", a);
return 0;
}
0.000000 ←Linux系统下的老式gcc
-13584010575872.000000 ←Turbo C 1.5
4008175468544.000000 ←XCode
4.5Visual Studio 2012、当前版本的gcc
/* 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; }
把一个类型的数值初始化给不同类型的变量时,编译器会把值转换成与变量匹配的类型,这将导致部分数据丢失。例如,下面的初始化:
int cost = 12.99; /* 用double类型的值初始化int类型的变量 */
float pi = 3.1415926536; /* 用double类型的值初始化float类型的变量 */
/* 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;
}
第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使光标移至下一行的起始处。
printf()语句把输出发送到一个叫作缓冲区(buffer)的中间存储区域,然后缓冲区中的内容再不断被发送到屏幕上。C标准明确规定了何时把缓冲区中的内容发送到屏幕:当缓冲区满、遇到换行字符或需要输入的时候(从缓冲区把数据发送到屏幕或文件被称为刷新缓冲区)。例如,前两个printf()语句既没有填满缓冲区,也没有换行符,但是下一条scanf()语句要求用户输入,这迫使printf()的输出被发送到屏幕上。
还有一种刷新缓冲区的方法是使用fflush()函数,详见第13章。
指出下面各种数据使用的合适数据类型(有些可使用多种数据类型):
a.East Simpleton的人口
b.DVD影碟的价格
c.本章出现次数最多的字母
d.本章出现次数最多的字母次数
在什么情况下要用long类型的变量代替int类型的变量?
使用哪些可移植的数据类型可以获得32位有符号整数?选择的理由是什么?
指出下列常量的类型和含义(如果有的话):
a.’\b’
b.1066
c.99.44
d.0XAA
e.2.0e30
Dottie Cawm编写了一个程序,请找出程序中的错误。
include <stdio.h>
main
(
float g; h;
float tax, rate;
g = e21;
tax = rate*g;
)
写出下列常量在声明中使用的数据类型和在printf()中对应的转换说明:
写出下列常量在声明中使用的数据类型和在printf()中对应的转换说明(假设int为16位):
假设程序的开头有下列声明:
int imate = 2;
long shot = 53456;
char grade = 'A';
float log = 2.71828;
把下面printf() 语句中的转换字符补充完整:
printf(“The odds against the %__ were %__ to 1.\n”, imate, shot);
printf(“A score of %__ is not an %__ grade.\n”, log, grade);
假设ch是char类型的变量。分别使用转义序列、十进制值、八进制字符常量和十六进制字符常量把回车字符赋给ch(假设使用ASCII编码值)。
修正下面的程序(在C中,/表示除以)。
void main(int) / this program is perfect /
{
cows, legs integer;
printf("How many cow legs did you count?\n);
scanf("%c", legs);
cows = legs / 4;
printf("That implies there are %f cows.\n", cows)
}
指出下列转义序列的含义:
a.\n
b.\
c."
d.\t
a.int类型,也可以是short类型或unsigned short类型。人口数是一个整数。
b.float类型,价格通常不是一个整数(也可以使用double类型,但实际上不需要那么高的精度)。
c.char类型。
d.int类型,也可以是unsigned类型。
原因之一:在系统中要表示的数超过了int可表示的范围,这时要使用long类型。原因之二:如果要处理更大的值,那么使用一种在所有系统上都保证至少是32位的类型,可提高程序的可移植性。
如果要正好获得32位的整数,可以使用int32_t类型。要获得可存储至少32位整数的最小类型,可以使用int_least32_t类型。如果要为32位整数提供最快的计算速度,可以选择int_fast32_t类型(假设你的系统已定义了上述类型)。
a.char类型常量(但是存储为int类型)
b.int类型常量
c.double类型常量
d.unsigned int类型常量,十六进制格式
e.double类型常量
第1行:应该是#include <stdio.h>
第2行:应该是int main(void)
第3行:把(改为{
第4行:g和h之间的;改成,
第5行:没问题
第6行:没问题
第7行:虽然这数字比较大,但在e前面应至少有一个数字,如1e21或1.0e21都可以。
第8行:没问题,至少没有语法问题。
第9行:把)改成}
除此之外,还缺少一些内容。首先,没有给rate变量赋值;其次未使用h变量;而且程序不会报告计算结果。虽然这些错误不会影响程序的运行(编译器可能给出变量未被使用的警告),但是它们确实与程序设计的初衷不符合。另外,在该程序的末尾应该有一个return语句。
下面是一个正确的版本,仅供参考:
#include <stdio.h>
int main(void)
{
float g, h;
float tax, rate;
rate = 0.08;
g = 1.0e5;
tax = rate * g;
h = g + tax;
printf("You owe $%f plus $%f in taxes for a total of $%f.\n", g, tax, h);
return 0;
}
7.
printf(“The odds against the %d were %ld to 1.\n”, imate, shot);
printf(“A score of %f is not an %c grade.\n”, log, grade);
ch = ‘\r’;
ch = 13;
ch = '\015’
ch = ‘\xd’
最前面缺少一行(第0行):#include <stdio.h>
第1行:使用/和/把注释括起来,或者在注释前面使用//。
第3行:int cows, legs;
第4行:count?\n");
第5行:把%c改为%d,把legs改为&legs。
第7行:把%f改为%d。
另外,在程序末尾还要加上return语句。
通过试验(即编写带有此类问题的程序)观察系统如何处理整数上溢、浮点数上溢和浮点数下溢的情况。
编写一个程序,要求提示输入一个ASCII码值(如,66),然后打印输入的字符。
编写一个程序,发出一声警报,然后打印下面的文本:
Startled by the sudden sound, Sally shouted,
“By the Great Pumpkin, what was that!”
编写一个程序,读取一个浮点数,先打印成小数点形式,再打印成指数形式。然后,如果系统支持,再打印成p记数法(即十六进制记数法)。按以下格式输出(实际显示的指数位数因系统而异):
Enter a floating-point value: 64.25
fixed-point notation: 64.250000
exponential notation: 6.425000e+01
p notation: 0x1.01p+6
一年大约有3.156×107秒。编写一个程序,提示用户输入年龄,然后显示该年龄对应的秒数。
1个水分子的质量约为3.0×10−23克。1夸脱水大约是950克。编写一个程序,提示用户输入水的夸脱数,并显示水分子的数量。
1英寸相当于2.54厘米。编写一个程序,提示用户输入身高(/英寸),然后以厘米为单位显示身高。
在美国的体积测量系统中,1品脱等于2杯,1杯等于8盎司,1盎司等于2大汤勺,1大汤勺等于3茶勺。编写一个程序,提示用户输入杯数,并以品脱、盎司、汤勺、茶勺为单位显示等价容量。思考对于该程序,为何使用浮点类型比整数类型更合适?
#include <stdio.h>
int main(void)
{
char ch;
printf("请输入一个ASII码:");
scanf("%d", &ch);
printf("%d对应的字符是%c", ch, ch);
return 0;
}
#include <stdio.h>
int main(void)
{
printf("\aStartled by the sudden sound, Sally shouted,\n\"By the Great Pumpkin, what was that!\"");
return 0;
}
#include <stdio.h>
int main(void)
{
float num;
printf("Enter a floating-point value:");
scanf("%f", &num);
printf("fixed-point notation: %f\n", num);
printf("exponential notation: %e\n", num);
printf("p notation: %a\n", num);
return 0;
}
#include<stdio.h>
int main(void)
{
int age;
printf("请输入您的年龄(整数):");
scanf("%d",age);
float second_of_year = 3.156E7;
printf("%d岁对应%e秒\n",age,age*second_of_year);
return 0;
}
#include <stdio.h>
int main(void)
{
float weightOfAH2OMolecule = 3.E-23;
double kuaTuo;
// 经验证,若是float类型可以计算1E13夸脱的水,大于将溢出,未防止溢出,声明未double变量,可以计算1的283次方夸脱
scanf("%f", &kuaTuo);
double numOfMolecule = kuaTuo * 950 / weightOfAH2OMolecule;
printf("%e夸脱的水中有%e个水分子", kuaTuo, numOfMolecule);
return 0;
}
#include <stdio.h>
int main(void)
{
float inch;
printf("请输入您的身高(英寸单位):");
scanf("%f", &inch);
printf("您的身高是%f", inch * 2.54);
return 0;
}
// 1品脱=2杯=16盎司=32大汤勺=96茶勺
#include <stdio.h>
int main(void)
{
float cup;
scanf("%f",&cup);
printf("%f杯等价于%f品脱,%f盎司,%f汤勺,%f茶勺\n", cup, cup / 2, 8 * cup, 16 * cup, 48 * cup);
return 0;
}
#include <stdio.h>
int main(void)
{
float inch;
printf("请输入您的身高(英寸单位):");
scanf("%f", &inch);
printf("您的身高是%f", inch * 2.54);
return 0;
}
// 1品脱=2杯=16盎司=32大汤勺=96茶勺
#include <stdio.h>
int main(void)
{
float cup;
scanf("%f",&cup);
printf("%f杯等价于%f品脱,%f盎司,%f汤勺,%f茶勺\n", cup, cup / 2, 8 * cup, 16 * cup, 48 * cup);
return 0;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。