При чтении из файла новые строки ломают мою очередь и методы push - PullRequest
0 голосов
/ 13 мая 2019
    FILE *fp = fopen(argv[2], "r");
        char input[80];
        if (fp == NULL) { 
            perror("Error");
            exit(1);
            fclose(fp);
        }

        Node* stack = NULL;
        Node* queue = NULL;

        while (fgets(input, 80, fp)) {
            const char *space = " \f\n\r\t\v";
            char* tokenS = strtok(input, space);

            while (tokenS != NULL) {
                printf("test %s\n", tokenS);
                queue = enqueue(queue, tokenS);
                stack = push(stack, tokenS);
                tokenS = strtok(NULL, space);
            }
        }
        printf("--Queue--\n");
        printList(queue);
        printf("--Stack--\n");
        printList(stack);

При чтении файла со словами, разделенными пробелом.Это работает, когда файл имеет только одну строку.Когда у меня несколько строк, я начинаю получать неожиданный вывод.Например, для ввода

hello world man bye boy
a

я получаю вывод.

test hello
test world
test man
test bye
test boy
test a
--Queue--
a
world
man
bye
boy
a
--Stack--
a
boy
bye
man
world
a

Я предполагаю, что это как-то связано с моими циклами?Я не совсем уверен.

РЕДАКТИРОВАТЬ: решено путем ввода значения токенов.Спасибо!

while (tokenS != NULL) {
                char* data = strdup(tokenS);
                printf("%s\n",data);
                queue = enqueue(queue, data);
                stack = push(stack, data);
                tokenS = strtok(NULL, space);
            }
        }

1 Ответ

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

Как объяснено в комментарии выше, при токенизации input с tokenS адрес, удерживаемый tokenS, указывает на адрес в пределах input.Когда вы снова вызываете fgets, все предыдущие указатели в конечном итоге указывают на новую информацию в input, поскольку вы перезаписали то, что было в input, при следующем вызове fgets.

Чтобы решитьпроблема, просто выделите хранилище для tokenS (скажем, в tokenScpy), а затем сохраните копию в stack и queue.Каждый tokenScpy будет указывать на отдельный блок памяти с выделенной продолжительностью хранения , и на него не будут влиять любые изменения, внесенные вами в input.(вы также несете ответственность за освобождение каждого блока с памятью больше не требуется)

Если у вас есть POSIX strdup, это может обеспечить выделение и копирование в один вызов.( но обратите внимание: strdup() выделяет, поэтому вы должны проверить, что выделение завершается успешно, как если бы вы сами звонили malloc().

С помощью strdup() вы можете сделать:

#define DELIM " \f\n\r\t\v"

    FILE *fp = fopen(argv[2], "r");
        char input[80];
        if (fp == NULL) { 
            perror("Error");
            exit(1);
            fclose(fp);
        }

        Node* stack = NULL;
        Node* queue = NULL;

        while (fgets(input, 80, fp)) {
            const char *space = DELIM;

            while (tokenS != NULL) {
                char *tokenScpy = strdup (tokenS);
                if (!tokenScpy) {   /* strdup allocate, you validate */
                    perror ("malloc-tokenScpy");
                    break;
                }
                printf("test %s\n", tokenScpy);
                queue = enqueue(queue, tokenScpy);
                stack = push(stack, tokenScpy);
                tokenS = strtok(NULL, DELIM);
            }
        }
        printf("--Queue--\n");
        printList(queue);
        printf("--Stack--\n");
        printList(stack);

( примечание: const char *space = " \f\n\r\t\v"; #define DELIM " \f\n\r\t\v" использовалось вместо *1035* просто из-за того, что space никогда не меняется, в любом случае это нормально)

Если strdup() недоступно, тогда простой вызов malloc и memcpy выполнит то же самое, например,

            while (tokenS != NULL) {
                size_t len = strlen (tokenS);
                char *tokenScpy = malloc (len + 1);
                if (!tokenScpy) {   /* validate every allocation */
                    perror ("malloc-tokenScpy");
                    break;
                }
                memcpy (tokenScpy, tokenS, len + 1);
                printf("test %s\n", tokenScpy);
                queue = enqueue(queue, tokenScpy);
                stack = push(stack, tokenScpy);
                tokenS = strtok(NULL, DELIM);
            }

Примечание: , как указывает г-н Леффлер, оба queue и stack будут хранить одну и ту же копию tokenScpy, что хорошо, если для каждого указателя вызывается только один free(). Если ваши стек и очередь у каждой подпрограммы есть свои free() сохраненных указателей - вам нужно будет сделать вторую копию каждого токена, чтобы у каждого была своя собственная копия. В этом случае вы могли бы сделать что-то похожее на:

        while (fgets(input, 80, fp)) {
            const char *space = DELIM;

            while (tokenS != NULL) {
                char *tokenScpys = strdup (tokenS),
                     *tokenScpyq = strdup (tokenS);
                /* strdup allocate, you validate */
                if (!tokenScpys || !tokenScpyq) {
                    perror ("malloc-tokenScpys/tokenScpyq");
                    break;
                }
                printf("tests %s  testq %s\n", tokenScpys, tokenScpyq);
                queue = enqueue(queue, tokenScpyq);
                stack = push(stack, tokenScpys);
                tokenS = strtok(NULL, DELIM);
            }
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...