Как читать неопределенное количество целых чисел из stdin построчно? - PullRequest
0 голосов
/ 17 мая 2019

Мне нужно прочитать и сохранить целые числа из стандартного ввода, используя C, полученный в следующем формате: «35: 27,5,10». В каждой строке записано неопределенное число целых чисел и определено неопределенное количество строк.В идеале я хотел бы иметь цикл, внутри которого я мог бы использовать значения из последней отсканированной строки для выполнения других задач.Как мне отсканировать и сохранить целые числа в массиве, а затем переписать массив при сканировании следующей строки и так далее, пока я не нажму EOF?

Я предполагаю, что должен использовать комбинацию scanf ()и strtok (), но я не могу понять, как это сделать.Я также пытался использовать getchar (), но это только усложняло вещи.

Ответы [ 3 ]

1 голос
/ 17 мая 2019

Эта программа читает файл этого формата (на 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;
}
0 голосов
/ 17 мая 2019

Полагаю, мне нужно использовать комбинацию scanf () и strtok ()

Я бы предположил иначе:

  • пользователь может ввести «почти бесконечное» количество нулей перед любым числом, или много пробелов, или много нулей после десятичной точки, или .... Это означает, что вы не можете ожидать ( например) иметь все цифры числа в оперативной памяти одновременно; это означает, что ни одна из функций, предоставляемых 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;
    }
}

Примечание. Пример кода не хранит никаких данных и вообще не обрабатывает пробелы (или десятичные точки, или ...) (для этого можно добавить больше кода и новые состояния) и т. Д. В основном; это «очень непроверенный» код, предназначенный только для примера.

0 голосов
/ 17 мая 2019

Я предполагаю, что мне нужно использовать комбинацию 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");
}
...