第四章 字符串和格式化输入、输出

目录

4.1 零碎基础知识

4.2 复习题

 4.3 编程题


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;
}
 

运行结果:

i ! What s your  name?  x i aozhou  xiaozhou , what' s your weight in pounds?  138  ell, xiaozhou,  your volume is 2. 21 cubic feet.  I so, your first name has 8 letters,  and we have 40 bytes to store it _

特别注意: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.hfloat.h分别提供了与整数类型和浮点类型大小限制相关的详细信息。每个头文件都定义了一系列供实现使用的明示常量

4.1 limits.h 中能找到的一些明示常量

CHAR  CHAR MAX  SCHAR MAX  SCHAR MIN  I.JCEAR MXX  sHRT MAX  SHRr MLN  MAX  MAX  Ltrr MLN  'JINT MAX  LONG MAX  LONG  IJL,ONG MXX  LLONG  LLONC  char  s Igned char  signed  unstqned char  ghort  short  unstqned short  int  int  unsiqned int  long  long long

 

FLT  FLT DIG  FLT 10 Exp  FLT  FLT MAX  FLT  *4.2 tbat_htFfKJ  float  float  float ID  float (VA IC  float  float  1.00

 

printf()scanf()

4.3 转换说明及其打印的输出结果

转 换 说 明  濘 点 、 十 六 还 数 和 p 记 去 ( ( 99 / ( 0 )  浮 点 数 、 十 进 制 和 p 记 懿 《 ( 99 / 〔 0 )  单 个 字  有 荇 号 十 制 堅 数  浮 点 , “ 记 数 法  淳 点 数 生 e 记 数 法  浮 点 《 t, 十 记 法  根 值 的 不 司 · 自 酚 擇 f 或 《 宀 氢@ 式 用 于 指 数 小 于 以 或 奢 大 于 等 于 度 时  格 式 于 指 数 小 于 一 4 或 为 大 于 或 等 于 精 度 时  银 值 的 不 司 · 过 动 选 f 或  有 荇 号 十 制 堅 数 ( 与 《 d 问 〕  老 荇 号 八 还 制 整 数  指 针  儿 蒜 号 十 进 制 堅 数  荇 号 十 六 进 制 鼕 数 · 用 十 六 湖 数 Of  光 荇 号 十 六 it 制 堅 , 绠 用 十 六 制 襲 OF  打 印 一 个 百 分 号

4.4 printf()的修饰符

'hhu "  "*jd". "88jx"  " •sad".  short int unsigned short int  signed char unsigned char  long unsigned long  long long unsigned long int (09)  , long double •k  "810.4Le•  ptrdift_t ptrdiff_t (C99)  size

4.5 printf()中的标记

标 记  含 义  待 印 左 齐 。 即 · 从 字 的 左 开 打 印 謹 項 項  示 到 : ” 生 一 20 。 "  有 号 值 菪 为 王 , 覲 在 值 前 面 是 示 加 号 : 为 到 在 值 前 面 显 示 滅 号  有 荇 亏 值 为 上 ,  在 值 前 面 示 耵 导 空 ( 不 是 示 任 何 荇 号 ); 茉 为 羊  + 记 覆 《 一 个 室 耩  示 洌 : ” 杰 6.2f "  把 能 果 为 另 一 科 形 式 · 如 罴 是 。 式 , 则 以 2 开 始 ; 如 果 是 又 或@泯 式 ,  对 十 所 有 的 点 幬 式 , , 讧 了 即 后 面 没 有 的 家 , 也 打 印 一 个 小 数 点 字 符 · 对 于 0 和 G 幬 人 ,  则 在 值 前 面 显 示 减 号  到 以 0 区 人 Ox 开 始 ;  仿 走 E 面 的 0 删 除  硇 410 。 3 “  对 于 数 愫 幬 式 · 前 导 0 代 替 空 地 段 河 度 。 对 于 整 数 式 , 如 摹 出 现 . 标 记 或 指 定 精 度 ,  诫 际 记  到 忽 略

 

printf给字符串断行有3种方法

  • 使用多个printf()语句
  • 用反斜杠(\)和Enter(或Return)键组合来断行
  • ANSI C引入的字符串连接。在两个用双引号括起来的字符串之间用空白隔开,C编译器会把多个字符串看作是一个字符串

 

print()函数和scanf()函数两个函数主要的区别在参数列表中。

printf()函数使用变量、常量和表达式,而scanf()函数使用指向变量的指针

 

4.6 ANSI Cscanf()的转换说明

转 換 谎 明  含 义  把 瞼 入 解 释 字  把 入 歲 有 荇 考 十 进 制 铧 数  把 0 入 载 享 点 数 忙 标 到 增 了 〕  把 0 入 萨 悻 浮 点 忙 标 唯 到 增 了 的  把 八 萨 懌 我 有 岳 号 十 迸 制 整 数  把 瞼 八 萨 成 有 科 号 八 进 韧 蘞  把 揄 入 成 针 〔 地 址 冫  把 揄 入 解 释 張 科 丰 . 从 第 《 个 啡 空 白 曱 廾 话 ,  恶 输 入  把 喻 入 歲 尢 捋 号 十 进 制 瓿  把 入 择 载 有 号 十 还 制 整 数  到 下 一 个 空 白 甘 之 榨 的 所 有

 

4.7 scanf()转换说明中的修饰符

"SIOS"  "thhd".  " thhu"  long Long (C99)

'•słx  uneigned int  unsigned  d. i. int44,  , Lntmax t uintmax t (C99)  . (09)

scanf()中把*放在%和转换字符之间时,会使得scanf()跳过相应的输出项。

4.2 复习题

1.再次运行程序清单 4.1,但是在要求输入名时,请输入名和姓(根据英文书写习惯,名和姓中间有一个空格),看看会发生什么情况?为什么?

输入姓名不加空格正常输出,光标提示下一条指令

i !What's your name?  i aozhou  iaozhou , what's your weight in pounds?

加了空格后程序结束

i !What's your name?  iao Zhou  iao , what's your we i ght in pounds?  el l, Xiao, your volume is —1720740. 00 cubic feet.  ISO, your first name has 4 letters,  nd we have 40 bytes to store it.

程序不能正常运行。

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;
}
 

运行结果:

lease enter your name.  i aozhou  Il r ight. xiaozhou. what's your age?  hat's a booboo! You must be at least 30.

5.假设一个程序的开头是这样:

#define BOOK "War and Peace"

int main(void)

{

float cost =12.99;

float percent = 80.0;

请构造一个使用BOOKcostpercentprintf()语句,打印以下内容:

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.字段宽度为15unsigned 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;
}

运行结果:

lease enter  i ao  lease enter  hou  our name is.  your last name  your first name:  Xiao. Zhou

 

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;
}
 

运行结果:

lease enter  lease enter  Zhou  our  our  our  our  name 1 s  name IS  name 1 s  name 1 s  your last name:  your first name:  x i aozhou "  x i aozhou"  x i aozhou  x i aozhou

 

3.编写一个程序,读取一个浮点数,首先以小数点记数法打印,然后以指数记数法打印。用下面的格式进行输出(系统不同,指数记数法显示的位数可能不同):

a.输入21.32.1e+001

b.输入+21.2902.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;
}

运行结果:

lease enter a float number :  1.3  In dec imal form: 21. 299999  he exponential form is: 2. 130000e+Ol

Please enter a float number .  21. 290  In decimal form: 21. 290001  he exponent ial form is: 2. 129000e+01

 

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;
}

运行结果:

P lease enter your he i ght (cm) :  h 76  Pabney. you are 1. 76m tal l.

 

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;
}

运行结果:

Please enter your  18. 12  Please enter your  At 18. 12 megabits  Down I oad speed (Mb/s)  Download size (MB) :  per second, a fi le of 2. 20 megabytes down loads in 0. 97 seconds.

 

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;
}

运行结果:

lease enter your lastname:  lease enter your firstname:  hou  iao Zhou  4  4  iao Zhou  4

 

7.编写一个程序,将一个double类型的变量设置为1.0/3.0,一个float类型的变量设置为1.0/3.0。分别显示两次计算的结果各3次:一次显示小数点后面6位数字;一次显示小数点后面12位数字;一次显示小数点后面16位数字。程序中要包含float.h头文件,并显示FLT_DIGDBL_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;
}

运行结果:

loat values:  . 333333 0. 333333343267  loat values:  . 333333 0. 333333333333  LT DIG: 6  BL DIG: 15  o. 3333333432674408  o. 3333333333333333

这两个宏在 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;
}

运行结果:

w8q2wf7Q77mSAAAAABJRU5ErkJggg==

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值