目录
4.1 零碎基础知识
示例代码:
#include <stdio.h>
#include <string.h> //提供strlen()函数的原型
#define DENSITY 62.4 //人体密度(单位:磅、立方英尺)
int main()
{
float weight;
char name[40] = { 0 }; //name是一个可容纳40个字符的数组
printf("Hi!What's your name?\n");
scanf_s("%s", name, 40);
printf("%s ,what's your weight in pounds?\n", name);
scanf_s("%f", &weight);
printf("Well,%s, your volume is %2.2f cubic feet.\n",
name, weight / DENSITY);
printf("Also, your first name has %d letters,\n",
strlen(name));
printf("and we have %d bytes to store it.\n",
sizeof(name));
return 0;
}
运行结果:
特别注意:scanf_s("%s", name, 40);
由于本人使用的是VS2019,版本已经弃用 scanf(), 用scanf_s() 代替,
scanf_s() 是针对“ scanf()在读取字符串时不检查边界,可能会造成内存泄露”这个问题设计的。scanf_s()用于读取字符串时,必须提供一个数字以表明最多读取多少位字符,以防止溢出。
警告 C6054 可能没有为字符串“name”添加字符串零终止符
解决办法:定义初始化:char name[40] = { 0 };
strlen()函数:获取字符串的长度
字符串常量"x"和字符常量'x'不同
区别之一在于'x'是基本类型(char),而"x"是派生类型(char数组);区别之二是"x"实际上由两个字符组成:'x'和空字符\0
明示常量
C头文件limits.h和float.h分别提供了与整数类型和浮点类型大小限制相关的详细信息。每个头文件都定义了一系列供实现使用的明示常量
表4.1 limits.h 中能找到的一些明示常量
printf()和scanf()
表4.3 转换说明及其打印的输出结果
表4.4 printf()的修饰符
表4.5 printf()中的标记
printf给字符串断行有3种方法
- 使用多个printf()语句
- 用反斜杠(\)和Enter(或Return)键组合来断行
- ANSI C引入的字符串连接。在两个用双引号括起来的字符串之间用空白隔开,C编译器会把多个字符串看作是一个字符串
print()函数和scanf()函数两个函数主要的区别在参数列表中。
printf()函数使用变量、常量和表达式,而scanf()函数使用指向变量的指针
表4.6 ANSI C中scanf()的转换说明
表4.7 scanf()转换说明中的修饰符
scanf()中把*放在%和转换字符之间时,会使得scanf()跳过相应的输出项。
4.2 复习题
1.再次运行程序清单 4.1,但是在要求输入名时,请输入名和姓(根据英文书写习惯,名和姓中间有一个空格),看看会发生什么情况?为什么?
输入姓名不加空格正常输出,光标提示下一条指令
加了空格后程序结束
程序不能正常运行。
第1 个scanf_s()语句只读取用户输入的名,而用户输入的姓仍留在输入缓冲区中(缓冲区是用于储存输入的临时存储区)。下一条scanf_s()语句在输入缓冲区查找重量时,从上次读入结束的地方开始读取。这样就把留在缓冲区的姓作为体重来读取,导致 scanf_s()读取失败。
另一方面,如果在要求输入姓名时输入xiaozhou 138,那么程序会把138作为用户的体重(虽然用户是在程序提示输入体重之前输入了138)。
2.假设下列示例都是完整程序中的一部分,它们打印的结果分别是什么?
a.printf("He sold the painting for $%2.2f.\n", 2.345e2);
He sold the painting for $234.50.
b.printf("%c%c%c\n", 'H', 105, '\41');
Hi!(注意,第1个字符是字符常量;第2个字符由十进制整数转换而来;第3个字符,反斜杠是转义字符,单字符表示时,可以用反斜杠与8进制数组合来表示。)
c.#define Q "His Hamlet was funny without being vulgar."
printf("%s\nhas %d characters.\n", Q, strlen(Q));
His Hamlet was funny without being vulgar.
has 42 characters.
d.printf("Is %2.2e the same as %2.2f?\n", 1201.0, 1201.0);
Is 1.20e+003 the same as 1201.00?
3.在第2题的c中,要输出包含双引号的字符串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(void)
{
int age;
char name[40] = { 0 };
int xp;
printf("Please enter your name.\n");
scanf_s("%s", name, 40);
printf("All right, %s, what's your age?\n", name);
scanf_s("%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.一个字段宽度与位数相同的十进制整数 %d
b.一个形如8A、字段宽度为4的十六进制整数 %4x
c.一个形如232.346、字段宽度为10的浮点数 %10.3f
d.一个形如2.33e+002、字段宽度为12的浮点数 %12.2e
e.一个字段宽度为30、左对齐的字符串 %-30s
7.打印下面各项内容要分别使用什么转换说明?
a.字段宽度为15的unsigned long类型的整数 %15lu
b.一个形如0x8a、字段宽度为4的十六进制整数 %#4x
c.一个形如2.33E+02、字段宽度为12、左对齐的浮点数 %-12.2e
d.一个形如+232.346、字段宽度为10的浮点数 %+10.3f
e.一个字段宽度为8的字符串的前8个字符 %8.8s
8.打印下面各项内容要分别使用什么转换说明?
a.一个字段宽度为6、最少有4位数字的十进制整数 %6.4d
b.一个在参数列表中给定字段宽度的八进制整数 %*o
c.一个字段宽度为2的字符 %2c
d.一个形如+3.13、字段宽度等于数字中字符数的浮点数 %+0.2f
e.一个字段宽度为7、左对齐字符串中的前5个字符 %-7.5s
9.分别写出读取下列各输入行的scanf()语句,并声明语句中用到变量和
数组。
a.101
int a; scanf_s("%d", &a);
b.22.32 8.34E−09
float b1, b2; scanf_s("%f%e", &b1, &b2);
c.linguini
char c[10] = {0}; scanf_s("%s", c, 10);
d.catch 22
e.catch 22 (但是跳过catch)
int e; scanf_s("%*d%d",&e);
10.什么是空白?
空白包括空格、制表符和换行符。C 语言使用空白分隔记号。scanf()使用空白分隔连续的输入项。
11.下面的语句有什么问题?如何修正?
printf("The double type is %z bytes..\n", sizeof(double));
%z 中的 z 是修饰符,不是转换字符,所以要在修饰符后面加上一个它修饰的转换字符。可以使用%zd打印十进制数,或用不同的说明符打印不同进制的数,例如,%zx打印十六进制的数。
12.假设要在程序中用圆括号代替花括号,以下方法是否可行?
#define ( {
#define ) }
可以分别把(和)替换成{和}。但是预处理器无法区分哪些圆括号应替换成花括号,哪些圆括号不能替换成花括号。因此,
#define ( {
#define ) }
int main(void)
(
printf("Hello, O Great One!\n");
)
将变成:
int main{void}
{
printf{"Hello, O Great One!\n"};
}
4.3 编程题
1.编写一个程序,提示用户输入名和姓,然后以“名,姓”的格式打印出来。
#include <stdio.h>
int main(void)
{
char last_name[10] = { 0 };
char first_name[10] = { 0 };
printf("Please enter your last name: \n");
scanf_s("%s", last_name, 10);
printf("Please enter your first name: \n");
scanf_s("%s", first_name, 10);
printf("Your name is: %s,%s", last_name, first_name);
return 0;
}
运行结果:
2.编写一个程序,提示用户输入名和姓,并执行一下操作:
a.打印名和姓,包括双引号;
b.在宽度为20的字段右端打印名和姓,包括双引号;
c.在宽度为20的字段左端打印名和姓,包括双引号;
d.在比姓名宽度宽3的字段中打印名和姓。
#include <stdio.h>
#include <string.h>
int main(void)
{
char last_name[10] = { 0 };
char first_name[10] = { 0 };
printf("Please enter your last name: \n");
scanf_s("%s", last_name, 10);
printf("Please enter your first name: \n");
scanf_s("%s", first_name, 10);
printf("Your name is: \"%s%s\"\n", last_name, first_name);
printf("Your name is: \"%*s%s\"\n",
+20 - strlen(first_name), last_name, first_name);
printf("Your name is: \"%s%*s\"\n",
last_name, -20 + strlen(first_name), first_name);
printf("Your name is: %*s%s\n",
strlen(last_name) + 3, last_name, first_name);
return 0;
}
运行结果:
3.编写一个程序,读取一个浮点数,首先以小数点记数法打印,然后以指数记数法打印。用下面的格式进行输出(系统不同,指数记数法显示的位数可能不同):
a.输入21.3或2.1e+001;
b.输入+21.290或2.129E+001;
#include <stdio.h>
#include <string.h>
int main(void)
{
float f_num;
printf("Please enter a float number: \n");
scanf_s("%f", &f_num);
printf("In decimal form: %f\n", f_num);
printf("The exponential form is: %e\n", f_num);
return 0;
}
运行结果:
4.编写一个程序,提示用户输入身高(单位:英寸)和姓名,然后以下面的格式显示用户刚输入的信息:
Dabney, you are 6.208 feet tall
使用float类型,并用/作为除号。如果你愿意,可以要求用户以厘米为单位输入身高,并以米为单位显示出来。
#include <stdio.h>
#include <string.h>
int main(void)
{
float height;
printf("Please enter your height(cm): \n");
scanf_s("%f", &height);
printf("Dabney, you are %.2fm tall.\n", height / 100);
return 0;
}
运行结果:
5.编写一个程序,提示用户输入以兆位每秒(Mb/s)为单位的下载速度和以兆字节(MB)为单位的文件大小。程序中应计算文件的下载时间。注意,这里1字节等于8位。使用float类型,并用/作为除号。该程序要以下面的格式打印 3 个变量的值(下载速度、文件大小和下载时间),显示小数点后面两位数字:
At 18.12 megabits per second, a file of 2.20 megabytes downloads in 0.97 seconds.
#include <stdio.h>
#include <string.h>
int main(void)
{
float d_speed, f_size, d_time;
printf("Please enter your Download speed(Mb/s): \n");
scanf_s("%f", &d_speed);
printf("Please enter your Download size(MB): \n");
scanf_s("%f", &f_size);
printf("At %.2f megabits per second,"
" a file of %.2f megabytes downloads in %.2f seconds.\n",
d_speed, f_size, f_size * 8 / d_speed);
return 0;
}
运行结果:
6.编写一个程序,先提示用户输入名,然后提示用户输入姓。在一行打印用户输入的名和姓,下一行分别打印名和姓的字母数。字母数要与相应名和姓的结尾对齐,如下所示:
Melissa Honeybee
7 8
接下来,再打印相同的信息,但是字母个数与相应名和姓的开头对齐,
如下所示:
Melissa Honeybee
7 8
#include <stdio.h>
#include <string.h>
int main(void)
{
char first_name[10] = { 0 },
last_name[10] = { 0 };
int num1, num2;
printf("Please enter your lastname:\n");
scanf_s("%s", last_name, 10);
printf("Please enter your firstname:\n");
scanf_s("%s", first_name, 10);
num1 = strlen(last_name), num2 = strlen(first_name);
printf("%s %s\n", last_name, first_name);
printf("%*d %*d\n", num1, num1, num2, num2);
printf("%s %s\n", last_name, first_name);
printf("%-*d %-*d\n", num1, num1, num2, num2);
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 f = 1.0 / 3.0;
double d = 1.0 / 3.0;
printf("float values:\n");
printf("%.6f %.12f %.16f\n", f, f, f);
printf("float values:\n");
printf("%.6f %.12f %.16f\n", d, d, d);
printf("FLT_DIG: %d\n", FLT_DIG);
printf("DBL_DIG: %d\n", DBL_DIG);
return 0;
}
运行结果:
这两个宏在 float.h 头文件下面,用来说明double、float两种数据类型有效数字的位数,注意不是小数点后面的有效位数,而是所有位数。
#define DBL_DIG 15 /* # of decimal digits of precision */
#define FLT_DIG 6 /* # of decimal digits of precision */
float能保证的有效位数最多是6~7位,完全能保证的是6位,double是15~16位,完全能保证的是15位。
8.编写一个程序,提示用户输入旅行的里程和消耗的汽油量。然后计算并显示消耗每加仑汽油行驶的英里数,显示小数点后面一位数字。接下来,使用1加仑大约3.785升,1英里大约为1.609千米,把单位是英里/加仑的值转换为升/100公里(欧洲通用的燃料消耗表示法),并显示结果,显示小数点后面 1 位数字。注意,美国采用的方案测量消耗单位燃料的行程(值越大越好),而欧洲则采用单位距离消耗的燃料测量方案(值越低越好)。使用#define 创建符号常量或使用 const 限定符创建变量来表示两个转换系数。
#include <stdio.h>
#define KM_MILE 1.609
#define L_GALLON 3.785
int main(void)
{
float mile, gallon;
printf("Please enter your travel mileage(miles):\n");
scanf_s("%f", &mile);
printf("Please enter the amount of gasoline consumed(gallon):\n");
scanf_s("%f", &gallon);
printf("Miles per gallon: %f(mile/gallon)\n", mile / gallon);
printf("Into Europe's general fuel consumption: %f(L/100km)",
(100 * L_GALLON * gallon) / (KM_MILE * mile));
return 0;
}
运行结果: