简体   繁体   English

输入行末尾的空格导致 while 循环到 go 比它应该多一次

[英]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;
}

This code is supposed to collect input like:此代码应该收集如下输入:

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 

First, there is some number, then one number and one word.首先,有一些数字,然后是一个数字和一个单词。 I don't know how many times will there be but I know the number of input lines.我不知道会有多少次,但我知道输入行的数量。 The problem I encountered is when there is a space at the end of input line right before pressing 'enter' in console, program keeps on waiting for more input.我遇到的问题是,在控制台中按“enter”之前,输入行末尾有一个空格,程序一直在等待更多输入。 I have no idea how to get rid of this especially at the last line of input because putting space at the end of last input line causes program to wait forever for a user to type something.我不知道如何摆脱这一点,尤其是在输入的最后一行,因为在最后一行的末尾放置空格会导致程序永远等待用户输入某些内容。

Let's unpack your code.让我们解压缩您的代码。

You're using getchar to look for an end of line, but it will swallow that character.您正在使用getchar查找行尾,但它会吞下该字符。 scanf cannot see it. scanf看不到它。 If you input "0123456789" getchar will eat the 0. You could use putchar to put it back, but it's all unnecessary.如果你输入“0123456789”, getchar会吃掉 0。你可以用putchar把它放回去,但这都是不必要的。

    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 .这是从输入中读取最多九个字符并将其粘贴到字符串arr中。 Then it's reading another nine characters from input and overwriting eight of the characters it just read.然后它从输入中读取另外 9 个字符并覆盖它刚刚读取的 8 个字符。

To walk through it, let's say the line is "0123456789abcdefghijklmno"要遍历它,假设该行是“0123456789abcdefghijklmno”

  • a: 0一个:0
  • stdin: "0123456789abcdefghijklmno\n"标准输入:“0123456789abcdefghijklmno\n”
  • arr: "garbagegarbagegarbagegarbage" // arr is uninitialized arr: "garbagegarbagegarbagegarbage" // arr 未初始化

getchar() reads 0 from stdin. getchar()从标准输入读取 0。

  • a: 0一个:0
  • stdin: "123456789abcdefghijklmno\n"标准输入:“123456789abcdefghijklmno\n”
  • arr: "garbagegarbagegarbagegarbage" arr:“垃圾垃圾垃圾”

scanf("%9s", &(arr[a])) reads 123456789 from stdin and puts it in arr starting at a which is 0. scanf("%9s", &(arr[a]))从标准输入读取 123456789 并将其放入arr a 0 开始。

  • a: 0一个:0
  • stdin: "abcdefghijklmno\n"标准输入:“abcdefghijklmno\n”
  • arr: "123456789\0rbagegarbagegarbage" 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 . scanf("%9s", &(arr[a + 1]))从标准输入读取 abcdefghi 并将其放入arra + 1开始,即 1 覆盖刚刚写入arr的第一个字符以外的所有字符。

  • a: 0一个:0
  • stdin: "jklmno\n"标准输入:“jklmno\n”
  • arr: "1abcdefghi\0bagegarbagegarbage" arr: "1abcdefghi\0bagegarbagegarbage"

arr[a] will be "1abcdefghi". arr[a]将是“1abcdefghi”。


char arr[1000] allocates space for a single string of 999 characters (plus a null byte) to the stack. char arr[1000]为堆栈中的 999 个字符(加上一个 null 字节)的单个字符串分配空间。 I think you mean arr to be an array of 1000 strings, each able to hold at least 9 characters plus the null byte.我认为您的意思是arr是一个包含 1000 个字符串的数组,每个字符串至少可以容纳 9 个字符加上 null 字节。 That's char arr[1000][10] .那是char arr[1000][10]

scanf has many problems , as does trying to read line-by-line with getchar . scanf有很多问题,尝试使用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.相反,通常最好使用fgets将一行读入缓冲区并使用sscanf或其他字符串解析函数解析该行。 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 (STRing TOKenizer) 在空白处分割行。 strtok behaves a little oddly because it has its own internal buffer. strtok的行为有点奇怪,因为它有自己的内部缓冲区。 It also does not allocate new memory, it returns pointers within the original line.它也不分配新的 memory,它返回原始行内的指针。 The spaces are replaced with null bytes so it seems like you're getting just one token at a time.空格被替换为 null 字节,所以看起来你一次只得到一个令牌。 Use strdup to copy the word into your array.使用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;
}

You should be able to adapt that basic code to read lines of words to your specific task.您应该能够调整该基本代码以根据您的特定任务读取单词行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM