У меня есть следующие данные:

1 (2 ,3 ,4) lantern

Количество входов типа int в круглых скобках неизвестно и может продолжаться некоторое время.

Моя первоначальная мысль заключалась в том, чтобы сканировать f () первый int, а затем создать цикл while, чтобы определить, когда сканируется закрытый паранетис. Затем, наконец, используйте fgets (), чтобы получить строку в конце, что-то вроде этого.

scanf("%d", &address);  //first input

scanf("%c", &paren);    //scan the '(' or ',' or ')'

int current_room = 0;   //index for array inside parenthsis

while(paren == '(' || paren == ','){

    scanf("%d,", adjoined_room[current_room]);  //scan am int

    scanf("%c", &paren);   //scan a ',' or ')'

    current_room++;        //increase the index

}

Однако это выводит следующий результат, когда я печатаю свой адрес, массив и строку:

Address: 1
Item: (2 ,3 ,4) lantern

Введенные в скобки целые числа никогда не устанавливались в массив. Есть ли лучший способ определить, когда вводится ")"?

-1
thatsquitemid 16 Сен 2021 в 22:19

3 ответа

Лучший ответ

Проблема в том, что scanf("%c", будет читать следующий символ во вводе, не пропуская пробелов. Если вы хотите пропустить пробелы, вам понадобится пробел в формате, например scanf(" %c",. Вы также должны проверить возвращаемое значение scanf, чтобы убедиться, что вы получили целое число

Добавление этого в свой код дает вам что-то вроде:

if (scanf("%d", &address) != 1) {  //first input
    fprintf(stderr, "syntax error\n");
    return;  // not an integer -- do something else
}
scanf(" %c", &paren);    //scan the '(' or ',' or ')'
int current_room = 0;   //index for array inside parenthsis
while(paren == '(' || paren == ','){
    if (scanf("%d", adjoined_room[current_room]) == 1) {  //scan an int
        current_room++;        //increase the index
    }
    scanf(" %c", &paren);   //scan a ',' or ')'
    if (paren != ',' && paren != ')') {
        fprintf(stderr, "syntax error\m");
        return;
    }
}

Если вы хотите сделать это с помощью интерактивного ввода, вам, вероятно, следует использовать fgets или getline для чтения целых строк и sscanf для независимого анализа каждой строки, чтобы не запутать пользователя, когда есть ошибка в середине строки. «Строка чтения + sscanf» также очень полезна, если у вас есть несколько различных шаблонов, которые вы хотите попробовать (sscanf в одной строке с разными форматами, чтобы найти первый подходящий).

2
Chris Dodd 16 Сен 2021 в 20:16

Никогда не следует использовать scanf. Всегда. Но .... вы можете попробовать что-то вроде:

#include <err.h>
#include <stdio.h>
#include <stdlib.h>

void * xrealloc(void *buf, size_t num, size_t siz);

int
main(void)
{
        size_t cap = 4;
        char buf[1024];
        int *x = xrealloc(NULL, cap, sizeof *x);
        if( scanf("%d ( %d", x, x + 1) != 2 ){
                errx(EXIT_FAILURE, "Ivalid input");
        }
        int *y = x + 2;
        while( scanf(",%d", y) == 1 ){
                if( ++y == x + cap ){
                        cap += 4;
                        x = xrealloc(x, cap, sizeof *x);
                }
        }
        if( scanf(")%1023s", buf) != 1 ){
                errx(EXIT_FAILURE, "Ivalid input");
        }
        for( unsigned i = 0; i < y - x; i += 1 ){
                printf("x[%d] = %d\n", i, x[i]);
        }
        printf("%s\n", buf);
        return 0;
}
void *
xrealloc(void *buf, size_t num, size_t siz)
{
        char *b = buf;
        b = realloc(b, num * siz);
        if( b == NULL ){
                perror("realloc");
                exit(EXIT_FAILURE);
        }
        return b;
}

Это неправильно обрабатывает ввод с запятой в конце, например: 1 (2 ,3 ,4, ) lantern, и я уверен, что есть много других вводов, которые ему не нравятся. Упражнение оставлено читателю.

Вероятно, вы не захотите использовать начальную емкость всего 4, но это удобно для простого тестирования.

0
William Pursell 16 Сен 2021 в 19:37

Возможно, это не самый популярный ответ, и он может помочь, а может и не помочь вашим ближайшим целям, но я придерживаюсь философии чтения ввода как потока байтов и синтаксического анализа через (грубый или сложный) конечный автомат:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define process_word(x) (printf("Got string \'%s\'\n", x))
#define process_number(x) (printf("Got number %lu\n", strtoul(x, NULL, 10)))

int main(void) {
        int c;
        int depth = 0;
        size_t i;
        char digitbuffer[256];
        char alphabuffer[256];

        while ((c = fgetc(stdin)) != EOF) {
                switch (c) {
                case ' ': 
                case ',':
                        break;
                case '(': 
                        depth++;
                        break;
                case ')':
                        if (depth == 0) perror("Mismatched parenthesis, skipping");
                        else depth--;
                        break;
                default:
                        if (isalpha(c)) {
                                memset(alphabuffer, 0, 256);
                                alphabuffer[0] = c;
                                i = 1;
                                while ((c = fgetc(stdin)) != EOF &&
                                    isalpha(c) &&
                                    i < 255) {
                                        alphabuffer[i++] = c;
                                }
                                if (!isalpha(c) && c != EOF) ungetc(c, stdin);
                                process_word(alphabuffer);
                        }
                        else if (isdigit(c)) {
                                memset(digitbuffer, 0, 256);
                                digitbuffer[0] = c;
                                i = 1;
                                while ((c = fgetc(stdin)) != EOF &&
                                    isdigit(c) &&
                                    i < 255) {
                                        digitbuffer[i++] = c;
                                }
                                if (!isdigit(c) && c != EOF) ungetc(c, stdin);
                                process_number(digitbuffer);
                        }
                        break;
                }
        }

        return 0;
}

На мой взгляд, это дает вам максимальный контроль над обработкой вашего конкретного формата данных.

Конечно, вы можете определить свои собственные функции process_word() и process_number(). process_number() может присвоить номер полю address записи, если, например, depth == 0, или добавить его в adjacent_room[], если depth == 1. process_word() может добавить строку в поле item той же записи. Полностью зависит от вас. ¯ \ _ (ツ) _ / ¯

0
torstenvl 16 Сен 2021 в 20:21