我似乎无法弄清楚输出结果如何。我正在读取多行用户输入并输出超出下边界的相应输入。出于某种原因,当我输出时,输出的字符串省略了字符串的第一个字符。谁能告诉我为什么会这样?
#include <stdio.h>
typedef struct{
char name[4];
int population;
} state;
enum { MAX_STATES = 10 };
int main()
{
state myStates[MAX_STATES];
int c;
int i = 0;
while ((c = getchar())!= EOF)
{
scanf("%s %d\n", myStates[i].name, &myStates[i].population);
i++;
}
// printf("Last character is [%d]\n", c);
printf("");
if (c <= 0)
{
for(int j = 0; j <= MAX_STATES; j++)
{
if(myStates[j].population >= 10)
printf("%s %d\n", myStates[j].name, myStates[j].population);
else
break;
}
}
return 0;
}
输入:
TX 23
CA 45
输出:
X 23
A 45
更新代码:
#include <stdio.h>
typedef struct{
char name[4];
int population;
} State;
enum { MAX_STATES = 10 };
int main()
{
State myStates[MAX_STATES];
int i, j;
// Function to read in multiple lines (up to 10) of user input; loop
// controls in place, detects format problems, prevents string buffer
// overflows.
for (i = 0; i < MAX_STATES; i++)
{
if (scanf("%2s %d\n", myStates[i].name, &myStates[i].population) != 2)
break;
}
// Function to output (stdout) array of State structs that exceed 10
// population.
for(j = 0; j < i; j++)
{
if(myStates[j].population >= 10)
printf("%s %d\n", myStates[j].name, myStates[j].population);
else
break;
}
return 0;
}
发布的输出,只有在输入小于10并且它突然出现循环时才会发送。当我没有那个break语句时,我在最后一行得到了垃圾输出。有什么建议可以提高产量吗?
答案 0 :(得分:6)
替换:
int i = 0;
while ((c = getchar()) != EOF)
{
scanf("%s %d\n", myStates[i].name, &myStates[i].population);
i++;
}
使用:
int i;
for (i = 0; i < MAX_STATES; i++)
{
if (scanf("%3s %d", myStates[i].name, &myStates[i].population) != 2)
break;
}
这可以防止您进入太多状态,使用for
循环将循环控件放在适当位置,检测格式问题,防止字符串缓冲区溢出,并将第一个字符读入名称。此外,如果以交互方式输入输入,则格式字符串中的尾随空格(例如空格或换行符)在scanf()
格式字符串中是一个非常糟糕的主意。如果输入来自文件,则不太严重,但在大多数情况下仍然是不必要的。 (有关详细信息,请参阅Trailing blank in scanf()
format。)
保持一段时间
如果您真的坚持需要while
循环,那么您可以使用:
int i = 0;
while (i < MAX_STATES && (c = getchar()) != EOF)
{
ungetc(c, stdin);
if (scanf("%3s %d", myStates[i].name, &myStates[i].population) != 2)
break;
i++;
}
或:
int i = 0;
while (i < MAX_STATES && (c = getchar()) != EOF)
{
myStates[i].name[0] = c;
if (scanf("%2s %d", &myStates[i].name[1], &myStates[i].population) != 2)
break;
i++;
}
请注意,这些while
循环仍然保留了大量溢出保护 - 溢出主阵列,并溢出名称字段。请注意,两个scanf()
语句中的一个使用%3s
,另一个%2s
;你应该能够解释原因。 (是的,scanf()
不计算空字节,因此您必须在转换规范中使用“逐个”长度。)
for
循环更接近于惯用语。
通常合理的一种替代方法是使用fgets()
(或POSIX getline()
(如果可用)来读取整行,然后sscanf()
来解析这些行。这通常会导致更具弹性的程序和更好的错误报告。它还阻止了那些试图将所有50个州的信息放在一条线上,或者将每个数据放在一条单独的线上并且在它们之间都有一条空行的人,从而避免使用格式错误的数据。你可以悄悄地坚持两个领域(如果你小心,只有两个领域)。
我可以询问有关正确显示输出的建议吗?
你有:
printf("");
if (c <= 0)
{
for(int j = 0; j <= MAX_STATES; j++)
{
if(myStates[j].population >= 10)
printf("%s %d\n", myStates[j].name, myStates[j].population);
else
break;
}
}
第一个printf()
什么也没做;它应该去。 if (c <= 0)
条件有点可疑。可以键入一个空字节(通常是 Control - @ 或 Control-Shift-2 ),尽管要破坏原始循环会有点难。 for
循环应该更像for (int j = 0; j < MAX_STATES; j++)
- 这是C中安全for
循环的模板。您最常使用for (int i = 0; i < MAX; i++)
。但是,您只想打印已读取的状态,因此您需要使用MAX_STATES
作为限制,而不是使用i
。如果你真的只想要打印前9个州(CA,TX,FL,NY,IL,PA,OH,GA,NC - 见Wikipedia;密歇根州只有10M,它说),那么if
条件没问题。
所以,您可以使用(注意输入循环将i
设置为成功读取的状态数):
for (int j = 0; j < i; j++)
printf("State: %.2s, Pop'n: %dM\n", myStates[j].name, myStates[j].population);
当然,您可以调整格式以满足您的要求。如果没有读取状态,或者读取的状态数,则不会打印任何内容。如果你真的想在人口中应用条件,那么你可以使用:
for (int j = 0; j < i; j++)
{
if (myStates[i].population >= 10)
printf("State: %.2s, Pop'n: %dM\n", myStates[j].name, myStates[j].population);
}
答案 1 :(得分:0)
您可以尝试在scanf中的%s之前添加空格,或指定严格数量的字符。
scanf(" %3s",
甚至可以像Beej's guide:
一样使用// read all whitespace, then store all characters up to a newline
scanf(" %[^\n]", s);
答案 2 :(得分:0)
另一种选择是:
int i = 0;
char temp[100];
for(i=0; i<MAX_STATES; i++){
fgets(temp, 100, stdin);
if(strcmp(temp, "\n") == 0)
break;
sscanf(temp, "%s %d\n", myStates[i].name, &myStates[i].population);
}
答案 3 :(得分:0)
您可以尝试在scanf中的%s之前添加空格,或指定严格数量的字符。
甚至可以使用它:
//读取所有空格,然后将所有字符存储到换行符
scanf(&#34;%[^ \ n]&#34;,s);