小结
字符串是一系列被视为一个处理单元的字符。在C语言中,字符串是以空字符(ASCII码是0)结尾的一系列字符。可以把字符串储存在字符数组中。数组是一系列同类型的项或元素。下面声明了一个名为name、有30个char类型元素的数组:
char name[30];
要确保有足够多的元素来储存整个字符串(包括空字符)。字符串常量是用双引号括起来的字符序列,如:"This is an example of astring"。
预处理器为预处理器指令(以#符号开始)查找源代码程序,并在开始编译程序之前处理它们。处理器根据#include指令把另一个文件中的内容添加到该指令所在的位置。
在程序中,最好用#define 定义数值常量,用 const 关键字声明的变量为只读变量(可以在计算中使用只读变量,可以打印只读变量,但是不能更改只读变量的值)。在程序中使用符号常量(明示常量),提高了程序的可读性和可维护性。
C 语言的标准输入函数(scanf())和标准输出函数(printf())。确保转换说明的数量和类型与函数的其余参数相匹配。对于scanf(),一定要记得在变量名前加上地址运算符(&)。另外,可以使用转换说明和修饰符控制输出的外观:字段宽度、小数位和字段内的布局。
空白字符(制表符、空格和换行符)在 scanf()处理输入时起着至关重要的作用。除了%c 模式(读取下一个字符),scanf()在读取输入时会跳过非空白字符前的所有空白字符,然后一直读取字符,直至遇到空白字符或与正在读取字符不匹配的字符。考虑一下,如果scanf()根据不同的转换说明读取相同的输入行,会发生什么情况。假设有如下输入行:
-13.45e12# 0
如果其对应的转换说明是%d,scanf()会读取3个字符(-13)并停在小数点处,小数点将被留在输入中作为下一次输入的首字符。
如果其对应的转换说明是%f,scanf()会读取-13.45e12,并停在#符号处,而#将被留在输入中作为下一次输入的首字符;然后,scanf()把读取的字符序列-13.45e12转换成相应的浮点值,并储存在float类型的目标变量中。
如果其对应的转换说明是%s,scanf()会读取-13.45e12#,并停在空格处,空格将被留在输入中作为下一次输入的首字符;然后,scanf()把这 10个字符的字符码储存在目标字符数组中,并在末尾加上一个空字符。
如果其对应的转换说明是%c,scanf()只会读取并储存第1个字符。
复习题
1.再次运行程序清单 4.1,但是在要求输入名时,请输入名和姓(根据英文书写习惯,名和姓中间有一个空格),看看会发生什么情况?为什么?
// 4-1程序
#include <stdio.h>
#include <string.h> // for strlen() prototype
#define DENSITY 62.4 // human density in lbs per cu ft
int main()
{
float weight, volume;
int size, letters;
char name[40]; // name is an array of 40 chars
printf("Hi! What's your first name?\n");
scanf("%s", name);
printf("%s, what's your weight in pounds?\n", name);
scanf("%f", &weight);
size = sizeof name;
letters = strlen(name);
volume = weight / DENSITY;
printf("Well, %s, your volume is %2.2f cubic feet.\n",
name, volume);
printf("Also, your first name has %d letters,\n",
letters);
printf("and we have %d bytes to store it.\n", size);
return 0;
}
程序不能正常运行。第1个scanf()语句只读取用户输入的名,而用户输入的姓仍留在输入缓冲区中(缓冲区是用于存储输入的临时存储区)。下一条scanf()语句在输入缓冲区查找重量时,从上次读入结束的地方开始读取。这样就把留在缓冲区的姓作为体重来读取,导致scanf()读取失败。另一方面,如果在要求输入姓名时输入Lasha144,那么程序会把144作为用户的体重(虽然用户是在程序提示输入体重之前输入了144)。
2.假设下列示例都是完整程序中的一部分,它们打印的结果分别是什么?
a.printf("He sold the painting for $%2.2f.\n", 2.345e2);
b.printf("%c%c%c\n", 'H', 105, '\41');
c.#define Q "His Hamlet was funny without being vulgar."
printf("%s\nhas %d characters.\n", Q, strlen(Q));
d.printf("Is %2.2e the same as %2.2f?\n", 1201.0, 1201.0);
a.He sold the painting for $234.50.
b.Hi!(注意,第1个字符是字符常量;第 2个字符由十进制整数转换而来;第 了个字符是八进制字符常量的 ASCII表示)
c. His Hamlet was funny without being vulgar.
has 42 characters.
d.Is 1.20e+003 the same as 1201.00?
3.在第2题的c中,要输出包含双引号的字符串Q,应如何修改?
在这条语句中使用\": printf("\"%s\"\nhas %d characters.\n",strlen(Q));
4.找出下面程序中的错误。
define B booboo
define X 10
main(int)
{
int age;
char name;
printf("Please enter your first name.");
scanf("%s", name);
printf("All right, %c, what's your age?\n", name);
scanf("%f", age);
xp = age + X;
printf("That's a %s! You must be at least %d.\n", B, xp);
rerun 0;
}
//修改的程序
#include <stdio.h>
#define B "booboo"
#define X 10
int main(int)
{
int age;
int xp;
char name[40]; //把name声明为数组
printf("Please enter your first name.");
scanf("%s", name);
printf("All right, %s, what's your age?\n", name);
scanf("%d", age);
xp = age + X;
printf("That's a %s! You must be at least %d.\n", B, xp);
return 0;
}
5.假设一个程序的开头是这样:
#define BOOK "War and Peace"
int main(void)
{
float cost =12.99;
float percent = 80.0;
请构造一个使用BOOK、cost和percent的printf()语句,打印以下内容:
This copy of "War and Peace" sells for $12.99.
That is 80% of list.
printf("This copy of \"%S\" sells for $%0.2f.\n",BOOK,cost);
printf("That is %0.0f%% of list.\n",percent);//要打印%必须用%%
6.打印下列各项内容要分别使用什么转换说明?
a.一个字段宽度与位数相同的十进制整数
b.一个形如8A、字段宽度为4的十六进制整数
c.一个形如232.346、字段宽度为10的浮点数
d.一个形如2.33e+002、字段宽度为12的浮点数
e.一个字段宽度为30、左对齐的字符串
a. %d
b. %4X
c. %10.3f
d. %12.2e
e. %-30s
7.打印下面各项内容要分别使用什么转换说明?
a.字段宽度为15的unsigned long类型的整数
b.一个形如0x8a、字段宽度为4的十六进制整数
c.一个形如2.33E+02、字段宽度为12、左对齐的浮点数
d.一个形如+232.346、字段宽度为10的浮点数
e.一个字段宽度为8的字符串的前8个字符
a. %lu
b. %#4X
c. %-12.2E
d. %+10.3f
8.打印下面各项内容要分别使用什么转换说明?
a.一个字段宽度为6、最少有4位数字的十进制整数
b.一个在参数列表中给定字段宽度的八进制整数
c.一个字段宽度为2的字符
d.一个形如+3.13、字段宽度等于数字中字符数的浮点数
e.一个字段宽度为7、左对齐字符串中的前5个字符
a. %6.4d
b. %*o
c. %2c
d. %+0.2f
e. %-7.5s
9.分别写出读取下列各输入行的scanf()语句,并声明语句中用到变量和数组。
a.101
b.22.32 8.34E−09
c.linguini
d.catch 22
e.catch 22 (但是跳过catch)
//a.
int dalmations;
scanf("%d",&dalmations);
//b.
float kgs,share;
scanf("%f%f"&kgs,&share);
(注意:对于本题的输入,可以使用转换字符e、f和g。另外,除了%c之外,在%和转换字符之间加空格不会影响最终的结果)
//c.
char pasta[20];scanf("%s",pasta);
//d.
char action[20];
int value;
scanf("%s %d",action,&value);
//e.
int value;
scanf("%s %d",&value);
10.什么是空白?
空白包括空格、制表符和换行符。C语言使用空白分隔记号。scanf()使用空白分隔连续的输入项。
11.下面的语句有什么问题?如何修正?
printf("The double type is %z bytes..\n", sizeof(double));
%z中的z是修饰符,不是转换字符,所以要在修饰符后面加上一个它修饰的转换字符。可以使
用%zd 打印十进制数,或用不同的说明符打印不同进制的数,例如,%zx打印十六进制的数。
12.假设要在程序中用圆括号代替花括号,以下方法是否可行?
#define ( {
#define ) }
可以分别把(和)替换成1和)。但是预处理器无法区分哪些圆括号应替换成花括号,哪些圆括号不能替换成花括号。因此,
#define( {
#define) }
int main(void)
(
printf("Hello,0 Great One!\n");
)
将变成:
int main{void}
{
printf{"Hello,O Great One!\n"};
}
编程练习
1.编写一个程序,提示用户输入名和姓,然后以“名,姓”的格式打印出来。
#include <stdio.h>
int main(void)
{
char fname[40];
char lname[40];
printf("Enter your first name: ");
scanf("%s", fname);
printf("Enter your last name: ");
scanf("%s", lname);
printf("%s, %s\n", lname, fname);
return 0;
}
4.编写一个程序,提示用户输入身高(单位:英寸)和姓名,然后以下面的格式显示用户刚输入的信息:
Dabney, you are 6.208 feet tall
使用float类型,并用/作为除号。如果你愿意,可以要求用户以厘米为单位输入身高,并以米为单位显示出来。
#include <stdio.h>
int main(void)
{
float height;
char name[40];
printf("Enter your height in inches: ");
scanf("%f", &height);
printf("Enter your name: ");
scanf("%s", name);
printf("%s, you are %.3f feet tall\n", name, height / 12.0);
return 0;
}
7.编写一个程序,将一个double类型的变量设置为1.0/3.0,一个float类型的变量设置为1.0/3.0。分别显示两次计算的结果各3次:一次显示小数点后面6位数字;一次显示小数点后面12位数字;一次显示小数点后面16位数字。程序中要包含float.h头文件,并显示FLT_DIG和DBL_DIG的值。1.0/3.0的值与这些值一致吗?
#include <stdio.h>
#include <float.h>
int main(void)
{
float ot_f = 1.0 / 3.0;
double ot_d = 1.0 / 3.0;
printf(" float values: ");
printf("%.6f %.12f %.16f\n", ot_f, ot_f, ot_f);
printf("double values: ");
printf("%.6f %.12f %.16f\n", ot_d, ot_d, ot_d);
printf("FLT_DIG: %d\n", FLT_DIG);
printf("DBL_DIG: %d\n", DBL_DIG);
return 0;
}