题目
给定n本书的名称和定价,本题要求编写程序,查找并输出其中定价最高和最低的书的名称和定价。
输入格式:
输入第一行给出正整数n(<10),随后给出n本书的信息。每本书在一行中给出书名,即长度不超过30的字符串,随后一行中给出正实数价格。题目保证没有同样价格的书。
输出格式:
在一行中按照“价格, 书名”的格式先后输出价格最高和最低的书。价格保留2位小数。
输入样例:
3
Programming in C
21.5
Programming in VB
18.5
Programming in Delphi
25.0
输出样例:
25.00, Programming in Delphi
18.50, Programming in VB
分析
题目不难,主要考察scanf和gets的使用。
scanf详细解答可以参考这篇文章scanf函数的使用。
首先想象输入设备(键盘)连接折一个叫做 “缓冲”的东西,把缓冲看作是一个字符数组(不是字符串哦)。
当程序执行到scanf
的时候,会从你的缓冲区读东西,如果缓冲区是空的,就阻塞住了,等待你从键盘输入。
scanf()
- 忽略先导空白符(空白符:空格符,制表符,回车符)
- 在读数据的时候看见空白符就会停止读入数据。
gets()
遇到回车符会停止读入,并将回车符转换成字符结束的标志。
gets
和 scanf
对比
- 功能
gets只有遇到换行符才会结束读入,scanf遇到空格符、制表符、换行符都会结束读入。
比如输入一个字符数组: I am a fish\n
gets 得到的 I am a fish\0
scanf 得到的 I - 停止读入后,处理的方式
比如 输入 test\nabcde
执行 gets 后, \n 不会留在缓冲区,这时候调用getchar()
得到的是 ‘a’;
执行 scanf 后, \n 会留在缓冲区,这时候调用getchar()
得到的是 ‘\n’。
这也是为什么之后的程序里在读入n的值之后要用一个 getchar()去吸收掉 换行符的原因了。
在使用VS编译器的时候,还会遇到一个warning
warning C4013: “gets”未定义;假设外部返回 int
因为函数gets
是ANSI C中的函数,其在读取时不检查边界,所以可能造成内存访问越界。例如分配了5个字节的空间,但读入了10个字节。
gets函数 在 C11 标准中已被移除.
但是如果忽视warning,使用gets函数,程序也会成功编译 运行成功。
为了安全起见,这里我们可以使用vs C++ 特有的函数 gets_s。
题解
#include <stdio.h>
#include <stdlib.h>
struct Book
{
char c[31];
double p;
};
typedef struct Book book;
int main()
{
int n = 0;
scanf("%d", &n);
book* b = (struct Book*)malloc(n * sizeof(struct Book));//动态分配内存 开辟数组
int i = 0, pmax = 0, pmin = 0; //假设最大价格最小价格的下标都是 0
for (i = 0; i < n; i++)
{
getchar(); //读入缓冲区的 \n
gets(b[i].c); //gets会一直读缓冲区中的字符,直到 \n 停止,把\n改成\0返回
scanf("%lf", &b[i].p);
if (b[i].p > b[pmax].p)
pmax = i;
if (b[i].p < b[pmin].p)
pmin = i;
}
printf("%.2f, %s\n", b[pmax].p, b[pmax].c);
printf("%.2f, %s", b[pmin].p, b[pmin].c);
free(b);
return 0;
}
在测试代码的时候,还有一个最长字符串的测试点,但是wrong了,然后把存放名字的数组的数组长度改为31就可以通过了。字符串长度不超过30,但是字符串末尾有一个字符串结束的标志符,所以至少需要31个的数组长度。