我想写一个程序,首先我输入一个数字N,然后我想逐个得到N个项目的名称(可以由多个单词组成(和价格。示例:
3
item a // the name can consist of multiple words
25.00
item b
12.50
item c
8.12
接下来我想处理这些数据,但是我被扫描部分卡住了。我的代码如下:
#include <stdio.h>
int main(){
int n;
char name[50];
int price;
scanf("%dn", &n);
for(int i = 0; i < n; i++){
scanf("%sn%d",name,&price);
printf("%s , %d", name, price);
}
printf("end");
}
这适用于单个单词项目,但如果项目中有空格,则不会继续扫描。我尝试使用gets()
函数,但是仍然没有得到正确的结果。代码:
for(int i = 0; i < n; i++){
gets(name);
scanf("%dn",&price);
printf("%s , %dn", name, price);
}
printf("end");
退货:
3 // Input 3 items
item a // name of first item
1 // price of item 1
item b // name of item 2
item a , 1 // the print of the first item
2 // price of item 2
item c // name of item 3
item b , 2 // print of item 2
3 // price of item 3
word // no clue where this new input came from
end // end of scanning
我的问题是,我该如何正确地扫描这样的输入?我还尝试将扫描函数更改为while((c = getchar()) != 'n');
,但得到了相同的结果。。。
混合gets()
和scanf()
是不好的,因为scanf()
往往会在stdin
中留下后面的'n'
。
使用gets()
是不好的。
scanf("%s", ...)
对于读取包含要保存的空格的信息行没有用处。
如何正确扫描这样的输入?
一个简单的替代方法是将每个行读取到字符串中,然后解析该字符串。
#include <stdio.h>
int main() {
char line[100];
int n;
fgets(line, sizeof line, stdin);
sscanf(line, "%d", &n);
for(int i = 0; i < n; i++){
char name[50];
// int price;
double price;
fgets(line, sizeof line, stdin);
sscanf(line, " %49[^n]", name);
fgets(line, sizeof line, stdin);
// sscanf(line, "%d", &price);
sscanf(line, "%lf", &price);
printf("%s , %.2fn", name, price);
}
printf("end");
}
高级:更好的代码将检查fgets(), sscanf()
的返回值。也许用strtod()
代替sscanf(line, "%lf",...
。
我认为,如果您添加更多的输出,您可能会很容易地弄清楚这里发生了什么。我们试试好吗?
此外,首先,您要查找的是双输入,而不是整数。使用整数时,您的扫描函数将无法根据您要查找的内容正确匹配。但是让我们添加更多的输出!
#include <stdio.h>
int main()
{
int n;
char name[50];
double price;
printf("Enter count: ");
scanf("%d", &n);
for (int i = 0; i < n; i++) {
printf("%sn", "Please type a name followed by a newline followed by a number and then press enter:");
scanf("%sn%lf", name, &price);
printf("%s , %lf", name, price);
}
return 0;
}
所以我认为你最初的尝试是多种因素的结合。大多数情况下,你可能在第一次迭代的输出后按下回车键?这将中断scanf调用,因为它不希望以n
开头,而是希望您立即输入名称。
其次,我不知道你在第一次迭代中输入的数字,因为你在使用scanf时没有提供它的输出,所以我只有猜测。你可能在第一次迭代时使用了整数,然后在剩下的迭代中选择使用小数?同样,这只是一个猜测。
有时只编写自己的函数并进行错误检查会更容易。以下是一个建议。您可能还需要检查这些数字是否为非负数。
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
void ReadLine(char result[], int resultLen)
{
int ch, i;
assert(resultLen > 0);
i = 0;
ch = getchar();
while ((ch != 'n') && (ch != EOF)) {
if (i < resultLen - 1) {
result[i] = ch;
i++;
}
ch = getchar();
}
result[i] = ' ';
}
void ReadInteger(int *i)
{
int ch, count;
count = scanf("%d", i);
if (count == 1) {
do {
ch = getchar();
} while (isspace(ch) && (ch != 'n'));
} else {
fprintf(stderr, "invalid input, integer expectedn");
exit(EXIT_FAILURE);
}
}
void ReadReal(double *x)
{
int ch, count;
count = scanf("%lf", x);
if (count == 1) {
do {
ch = getchar();
} while (isspace(ch) && (ch != 'n'));
} else {
fprintf(stderr, "invalid input, real number expectedn");
exit(EXIT_FAILURE);
}
}
int main(void)
{
char name[50];
int n;
double price;
ReadInteger(&n);
for (int i = 0; i < n; i++) {
ReadLine(name, sizeof name);
ReadReal(&price);
printf("%s, %.2fn", name, price);
}
return 0;
}
正如chux
在这个答案的评论中所说:">除%c、%[、%n外,所有扫描说明符都消耗前导空格。"所以您不需要考虑它们。
scanf("%s%d",name,&price);
根据您的输入,您应该使用float
或double
作为价格。
scanf("%s%lf",name,&price);
请注意,只有当项目由一个单词组成时,这才有效。如果它们可以是两个或多个单词,你最好使用fgets
编辑:对于由更多单词组成的项目,您应该使用fgets
fgets(name, 50, stdin);
scanf("%lf",&price);
将for循环替换为:
for (int i = 0; i < n; i++) {
scanf(" %[^n]n%d", name, &price);
printf("%s , %dn", name, price);
}
第一个空格跳过前导空格,[^\n]允许您获得多个单词作为字符串输入。