Space 在输入行的末尾导致 while 循环比它应该多运行一次
Space at the end of input line causes while loop to go one more time than it should
#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' 之前输入行末尾有一个 space 时,程序一直在等待更多输入。我不知道如何摆脱这种情况,尤其是在输入的最后一行,因为将 space 放在最后一行的末尾会导致程序永远等待用户输入内容。
让我们解压您的代码。
您正在使用 getchar
寻找行尾,但它会吞下该字符。 scanf
看不到。如果你输入“0123456789”getchar
会吃掉0。你可以用putchar
把它放回去,但这都是不必要的。
scanf("%9s", &(arr[a]));
scanf("%9s", &(arr[a + 1]));
这是从输入中读取最多九个字符并将其粘贴到字符串 arr
中。然后它从输入中读取另外九个字符并覆盖刚刚读取的八个字符。
为了遍历它,假设该行是“0123456789abcdefghijklmno”
- 一个:0
- 标准输入:“0123456789abcdefghijklmno\n”
- arr: "garbagegarbagegarbagegarbage" // arr 未初始化
getchar()
从标准输入读取 0。
- 一个:0
- 标准输入:“123456789abcdefghijklmno\n”
- arr: "垃圾垃圾垃圾垃圾"
scanf("%9s", &(arr[a]))
从 stdin 读取 123456789 并将其放入 arr
从 a
开始,即 0.
- 一个:0
- 标准输入:“abcdefghijklmno\n”
- arr: "123456789[=98=]rbagegarbagegarbage"
scanf("%9s", &(arr[a + 1]))
从 stdin 读取 abcdefghi 并将其放入 arr
从 a + 1
开始,这是 1 覆盖除了刚写入 arr
的第一个字符之外的所有字符.
- 一个:0
- 标准输入:“jklmno\n”
- arr: "1abcdefghi[=100=]bagegarbagegarbage"
arr[a]
将是“1abcdefghi”。
char arr[1000]
将 space 的 999 个字符(加上一个空字节)的单个字符串分配到堆栈。我认为你的意思是 arr
是一个包含 1000 个字符串的数组,每个字符串至少可以包含 9 个字符加上空字节。那是 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
放入缓冲区并使用 sscanf
或其他字符串解析函数解析该行。这避免了挂起等待输入或未知行大小的许多问题。
在这种情况下,使用 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
将单词复制到数组中。
#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;
}
您应该能够调整该基本代码以根据您的特定任务阅读单词行。
#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' 之前输入行末尾有一个 space 时,程序一直在等待更多输入。我不知道如何摆脱这种情况,尤其是在输入的最后一行,因为将 space 放在最后一行的末尾会导致程序永远等待用户输入内容。
让我们解压您的代码。
您正在使用 getchar
寻找行尾,但它会吞下该字符。 scanf
看不到。如果你输入“0123456789”getchar
会吃掉0。你可以用putchar
把它放回去,但这都是不必要的。
scanf("%9s", &(arr[a]));
scanf("%9s", &(arr[a + 1]));
这是从输入中读取最多九个字符并将其粘贴到字符串 arr
中。然后它从输入中读取另外九个字符并覆盖刚刚读取的八个字符。
为了遍历它,假设该行是“0123456789abcdefghijklmno”
- 一个:0
- 标准输入:“0123456789abcdefghijklmno\n”
- arr: "garbagegarbagegarbagegarbage" // arr 未初始化
getchar()
从标准输入读取 0。
- 一个:0
- 标准输入:“123456789abcdefghijklmno\n”
- arr: "垃圾垃圾垃圾垃圾"
scanf("%9s", &(arr[a]))
从 stdin 读取 123456789 并将其放入 arr
从 a
开始,即 0.
- 一个:0
- 标准输入:“abcdefghijklmno\n”
- arr: "123456789[=98=]rbagegarbagegarbage"
scanf("%9s", &(arr[a + 1]))
从 stdin 读取 abcdefghi 并将其放入 arr
从 a + 1
开始,这是 1 覆盖除了刚写入 arr
的第一个字符之外的所有字符.
- 一个:0
- 标准输入:“jklmno\n”
- arr: "1abcdefghi[=100=]bagegarbagegarbage"
arr[a]
将是“1abcdefghi”。
char arr[1000]
将 space 的 999 个字符(加上一个空字节)的单个字符串分配到堆栈。我认为你的意思是 arr
是一个包含 1000 个字符串的数组,每个字符串至少可以包含 9 个字符加上空字节。那是 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
放入缓冲区并使用 sscanf
或其他字符串解析函数解析该行。这避免了挂起等待输入或未知行大小的许多问题。
在这种情况下,使用 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
将单词复制到数组中。
#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;
}
您应该能够调整该基本代码以根据您的特定任务阅读单词行。