c - 输入行末尾的空格导致while循环比它应该多走一次
问题描述
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int a = 0, f = 0;
char ch[1];
char arr[1000];
while (f < 3) {
while (((*ch = getchar()) != 10))
{
scanf("%9s", &(arr[a]));
scanf("%9s", &(arr[a + 1]));
a += 2;
}
f++;
}
for (int i = 0; i < a; i++) {
printf("%s\n", &arr[i]);
}
return 0;
}
此代码应该收集如下输入:
1 4 green 4 green 1 blue 2 blue 4 blue 5 blue 7 blue 5 red 7 red 1 violet 2 violet 4 violet 5 violet 7 violet
1
2 4 green 4 green 7 blue 1 red 2 red 4 red 5 red 7 red 1 violet 2 violet 4 violet 5 violet 7 violet
2
3 4 green 4 green 1 blue 2 blue 4 blue 7 blue 1 red 2 red 4 red 5 red 7 red 5 violet 7 violet
3
首先,有一些数字,然后是一个数字和一个单词。我不知道会有多少次,但我知道输入行的数量。我遇到的问题是,在控制台中按“enter”之前,输入行末尾有一个空格,程序一直在等待更多输入。我不知道如何摆脱这一点,尤其是在输入的最后一行,因为在最后一行的末尾放置空格会导致程序永远等待用户输入某些内容。
解决方案
Let's unpack your code.
You're using getchar
to look for an end of line, but it will swallow that character. scanf
cannot see it. If you input "0123456789" getchar
will eat the 0. You could use putchar
to put it back, but it's all unnecessary.
scanf("%9s", &(arr[a]));
scanf("%9s", &(arr[a + 1]));
This is reading up to nine characters from input and sticking it into the string arr
. Then it's reading another nine characters from input and overwriting eight of the characters it just read.
To walk through it, let's say the line is "0123456789abcdefghijklmno"
- a: 0
- stdin: "0123456789abcdefghijklmno\n"
- arr: "garbagegarbagegarbagegarbage" // arr is uninitialized
getchar()
reads 0 from stdin.
- a: 0
- stdin: "123456789abcdefghijklmno\n"
- arr: "garbagegarbagegarbagegarbage"
scanf("%9s", &(arr[a]))
reads 123456789 from stdin and puts it in arr
starting at a
which is 0.
- a: 0
- stdin: "abcdefghijklmno\n"
- arr: "123456789\0rbagegarbagegarbage"
scanf("%9s", &(arr[a + 1]))
reads abcdefghi from stdin and puts it in arr
starting at a + 1
which is 1 overwriting all but the first character of what was just written to arr
.
- a: 0
- stdin: "jklmno\n"
- arr: "1abcdefghi\0bagegarbagegarbage"
arr[a]
will be "1abcdefghi".
char arr[1000]
allocates space for a single string of 999 characters (plus a null byte) to the stack. I think you mean arr
to be an array of 1000 strings, each able to hold at least 9 characters plus the null byte. That's char arr[1000][10]
.
scanf
has many problems, as does trying to read line-by-line with getchar
. Instead, it's usually better to read a line with fgets
into a buffer and parse the line with sscanf
or other string parsing functions. This avoids many issues with hanging waiting for input or unknown line size.
In this case, use strtok
(STRing TOKenizer) to split the line on whitespace. strtok
behaves a little oddly because it has its own internal buffer. It also does not allocate new memory, it returns pointers within the original line. The spaces are replaced with null bytes so it seems like you're getting just one token at a time. Use strdup
to copy the word into your array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
// A single line buffer to reuse.
// BUFSIZ is the size of the input buffer and a good size to choose.
char line[BUFSIZ];
// An array for 1000 strings.
// No memory is allocated for the strings themselves.
// We'll allocate as needed.
//
// Note: a real problem would not allocate a fixed size array.
// It would extend `words` as needed.
// You'll learn how to do that that later.
char *words[1000];
// Track how many words are in the words array.
int num_words = 0;
// Read at most 3 lines
for(int i = 0; i < 3; i++) {
// Read a line. Exit the loop early if there's no more lines.
if( !fgets(line, sizeof(line), stdin) ) {
break;
}
// Split the line on whitespace.
// fgets() does not strip newlines.
// We must include newline else it will be considered a word.
for(
char *word = strtok(line, " \t\n");
word;
word = strtok(NULL, " \t\n")
) {
// word is a pointer to memory inside line.
// The whitespace has been replaced by a null byte so we can
// read a single word. We could store that and save memory,
// but `line` will be reused to read the next line and
// the previous words will be overwritten.
// So we need to copy the word. `strdup` allocates just the
// right amount of memory.
words[num_words] = strdup(word);
num_words++;
}
}
for (int i = 0; i < num_words; i++) {
printf("%s\n", words[i]);
}
return 0;
}
You should be able to adapt that basic code to read lines of words to your specific task.
推荐阅读
- python - 在标签 data-reactid 上使用 python 从 espn 中提取数据
- vcf-vcard - 使用链接到图像文件的 URL 导入的“PHOTO”创建 VCF 文件
- javascript - 如何使用 URL-name 获取对象属性的值?
- typescript - VueJS - 只渲染一次组件
- python - 为什么这会输出为 1 2 6 24 而不是 24 6 2 1
- r - Dplyr 和 tidyverse - 变量模式之间的相关性(相同变量 VAR1_time1 和 VAR1_time2)
- python - Django 迁移:不反映变化 | 仅创建 id
- arrays - 为什么数组的总和不正确?
- xml - XSLT:使用 for-each-group 分组
- html - 如何使左/右图像/文本布局响应为上/下布局?