如何从stdin逐行读取未定义数量的整数?

时间:2019-05-17 02:28:03

标签: c int scanf stdin

我需要使用以下格式的C接收和输入来自标准输入的整数,并存储这些整数:“ 35:27,5,10”每行上有不确定数量的整数,行数也不确定。理想情况下,我希望有一个循环,可以在其中使用最近扫描的行中的值执行其他任务。我该如何扫描整数并将其存储在数组中,然后在扫描下一行时覆盖数组,依此类推,直到遇到EOF为止。

我想我必须同时使用scanf()和strtok(),但是我似乎不知道该怎么做。我也尝试过使用getchar(),但这只会使事情更加复杂。

3 个答案:

答案 0 :(得分:1)

如果发现意外情况,此程序将读取该格式的文件(在stdin上),并发出错误消息。

//sumline.c  sum integers on each line.
#include <stdio.h>
int main(){
  int sum=0;
  int rowcount=0;
  char buf[30]="";
  while(! feof(stdin) )
  { 
    int in;
    char sep[2];
    if((scanf("%1[^0-9-+]",sep)) && !feof(stdin))
    {
        fgets(buf,30,stdin);
        printf("unexpected %d char (%c,%30s)\n",sep[0],sep[0],buf);
        return 1;
    }
    if( ! scanf("%d",&in))
    {
        printf("malformed int\n");
        return 1;
    }
    if( feof(stdin) && rowcount == 0 )
    {
        return 0;
    }
    sum += in;
    if( ! scanf("%1[,:.\n]",sep) && !feof(stdin))
    {
        fgets(buf,30,stdin);
        printf("inexpected char %30s\n",buf);
        return 1;
    }
    else    
    {
      ++rowcount;
    }

    if( sep[0]=='\n' && rowcount )
    {
        printf("sum=%d\n",sum);
        sum=0;
        rowcount=0;
    }

    if( feof(stdin) && rowcount == 0 )
    {
        return 0;
    }
  }
return 0;
}

答案 1 :(得分:0)

  

我想我必须同时使用scanf()和strtok()

使用fgets()读取行,并使用sscanf()扫描读取的行以获取整数:

#include <stddef.h>  // size_t
#include <stdlib.h>  // realloc(), free()
#include <stdio.h>   // fgets(), sscanf(), printf(), puts(), fputs()

int main(void)
{
    char line_buffer[100];          // a buffer for the current line
    int *values_buffer = NULL;      // pointer to memory to store the values in
    size_t values_buffer_size = 0;  // actual size of the value buffer

    // while a line can be read from stdin ...
    while (fgets(line_buffer, sizeof line_buffer / sizeof *line_buffer, stdin)) {
        size_t num_values = 0;    // to count the values we're able to extract
        char *pos = line_buffer;  // the current read-position inside line_buffer

        // try to extract integers from the line_buffer at position pos:
        for (int consumed = 0, value;
             sscanf(pos, "%d%*[^0123456789]%n", &value, &consumed) >= 1;
             pos += consumed)
        {
            // %*[^0123456789] discards a string not containing any digit
            // %n yields the number of characters consumed

            // if the value_buffer isn't big enough ...
            if (num_values >= values_buffer_size) {
                // resize it
                int *tmp = realloc(values_buffer, (num_values + 1) * sizeof *tmp);
                if (!tmp) {
                    fputs("Not enough memory. :(", stderr);
                    free(values_buffer);
                    return EXIT_FAILURE;
                }
                // ... and update it's size
                values_buffer_size = num_values + 1;
                values_buffer = tmp;
            }

            // save the current value in value_buffer
            values_buffer[num_values++] = value;
        }

        // have fun with the values of the current line:
        if (num_values) {
            printf("Values: ");
            for (size_t i = 0; i < num_values; ++i)
                printf("%d ", values_buffer[i]);
            putchar('\n');
        } else puts("No values. :(\n");
    }

    // clean-up:
    free(values_buffer);

    if (ferror(stdin)) {
        fputs("An input error occured. :(\n", stderr);
        return EXIT_FAILURE;
    }
    else if (feof(stdin))
        puts("EOF reached.\n");
}

答案 2 :(得分:0)

  

我想我必须同时使用scanf()和strtok()

否则我会假设:

  • 用户可以在任何数字前输入“几乎无限”的零,或者在空白处输入很多,或者在小数点后输入很多零,或者...。这意味着您不能期望(例如)将一个数字的所有数字同时存储在RAM中;这意味着C提供的功能都不可用。

  • 发生错误。解析文本时,无论文本来自用户(需要知道为什么不喜欢他们的文本)还是来自文件或另一台计算机(开发人员需要能够在其中使用),都应将明确和描述性的反馈视为强制性的查找/修复问题)。

最好是避免两个问题都在于状态机处于循环状态。也许吧:

int state = NEWLINE;
unsigned int lineNumber = 0;
unsigned int dataNumber;

while( ((c = getChar()) != EOF)) && (state != ERROR) ) {
    switch(state) {
        case NEWLINE:
            lineNumber++;
            if(isDigit(c) {
                number = c - '0';
                state = FIRST_NUMBER_STARTED;
                dataNumber = 1;
            } else {
                printf("ERROR: Character at start of line is not a valid decimal digit\n");
                state = ERROR;
            }
            break;
        case FIRST_NUMBER_STARTED:
            if(isDigit(c) {
                digit = c - '0';
                if(number > UINT_MAX/10) {
                    printf("ERROR: First number on line %u is too large\n", lineNumber);
                    state = ERROR;
                } else {
                    number *= 10;
                    if(number > UINT_MAX - digit) {
                        printf("ERROR: First number on line %u is too large\n", lineNumber);
                        state = ERROR;
                    } else {
                        number += digit;
                    }
                }
            } else if(c == ';') {
                state = COLON_FOUND;
            } else {
                printf("ERROR: Invalid character after first number on line\n");
                state = ERROR;
            }
            break;
        case COLON_FOUND:
            if(isDigit(c) {
                number = c - '0';
                state = DATA_NUMBER_STARTED;
            } else {
                printf("ERROR: Character at start of data not a valid decimal digit\n");
                state = ERROR;
            }
            break;
        case DATA_NUMBER_STARTED:
            if(isDigit(c) {
                digit = c - '0';
                if(number > UINT_MAX/10) {
                    printf("ERROR: Data number %u on line %u is too large\n", dataNumber, lineNumber);
                    state = ERROR;
                } else {
                    number *= 10;
                    if(number > UINT_MAX - digit) {
                        printf("ERROR: Data number %u on line %u is too large\n", dataNumber, lineNumber);
                        state = ERROR;
                    } else {
                        number += digit;
                    }
                }
            } else if(c == ',') {
                state = COMMA_FOUND;
            } else if(c == '\n') {
                state = NEW_LINE;
            } else {
                printf("ERROR: Invalid character after data number %u on line %u\n", dataNumber, lineNumber);
                state = ERROR;
            }
            break;
        case COMMA_FOUND:
            dataNumber++;

            if(isDigit(c) {
                number = c - '0';
                state = FIRST_NUMBER_STARTED;
            } else if(c == '\n') {
                printf("ERROR: Missing number after comma at end of line %u\n", lineNumber);
                state = ERROR;
            } else {
                printf("ERROR: Invalid character after comma (after data number %u) on line %u\n", dataNumber-1, lineNumber);
            }
            break;
    }
}

注意:示例代码根本不存储任何数据,也根本不处理空格(或小数点或...)(您可以为其添加更多代码和新状态),等等。它是“未经测试”的代码,仅供参考。