扫描C中的不同数据类型

  • 本文关键字:数据类型 扫描 c
  • 更新时间 :
  • 英文 :


我想写一个程序,首先我输入一个数字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);

根据您的输入,您应该使用floatdouble作为价格。

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]允许您获得多个单词作为字符串输入。

最新更新