C 如何逐行从标准输入中读取未定义数量的整数?

C 如何逐行从标准输入中读取未定义数量的整数?,c,int,scanf,stdin,C,Int,Scanf,Stdin,我需要使用C从标准输入中读取并存储整数,接收格式如下:35:27,5,10每行上有未定义的整数数和未定义的行数。理想情况下,我希望有一个循环,在其中我可以使用最近扫描的行中的值来执行其他任务。如何扫描并存储数组中的整数,然后在扫描下一行时覆盖数组,依此类推,直到达到EOF 我想我必须使用scanf和strtok的组合,但我似乎不知道如何使用。我也尝试过使用getchar,但这只会让事情变得更复杂 我想我必须使用scanf和strtok的组合 使用fgets读取行,使用sscanf扫描读取的行以查

我需要使用C从标准输入中读取并存储整数,接收格式如下:35:27,5,10每行上有未定义的整数数和未定义的行数。理想情况下,我希望有一个循环,在其中我可以使用最近扫描的行中的值来执行其他任务。如何扫描并存储数组中的整数,然后在扫描下一行时覆盖数组,依此类推,直到达到EOF

我想我必须使用scanf和strtok的组合,但我似乎不知道如何使用。我也尝试过使用getchar,但这只会让事情变得更复杂

我想我必须使用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");
}

如果发现意外情况,此程序将在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;
}
我想我必须使用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;
    }
}

注意:示例代码不存储任何数据,也不处理空格或小数点,或者。。。你可以添加更多的代码和新的状态,等等;这是一段未经测试的代码,仅作为示例。

只需使用scanf,但要注意每个整数后面的内容,如果“\n”是行的结尾,那么它可能会很有用。因此,您实际上并不关心未定义的行数,因为您将单独处理每一行。您只需要知道每行上有多少个整数以及它们是什么。据推测,32位有符号int值足够大,可以容纳一行中的整数数量,或者您需要在一行中容纳多个千兆字节的数据吗?值是否也在int 32位带符号整数的范围内?有负值吗?除了冒号、逗号和换行符之外,还有其他分隔符吗?您还没有展示您尝试过的内容。嗯-前导的非“\n”空格会导致。似乎很严格,但符合OP的目标。有人抱怨scanf%d没有检查“\n”,因此我更改了循环的顺序。如果一个文件被要求有这样或那样的格式,如果我输入'0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001'作为第一个整数,这是一个好主意。会发生什么?scanf不是由这么长的整数混合而成的,您正在使用FGET将队列切分为多个块。