Как отделить разделитель вводимых пользователем слов от пробела с помощью strtok

Почему я получаю сообщение об ошибке сегментации после прочтения только одного слова?

Если я ввожу "почему это не работает"

я только вернусь

Зачем

и тогда я получаю ошибку сегментации.

Я видел другие примеры, но ни один из них не использовал пользовательский ввод, как я пытаюсь сделать здесь. Я могу прочитать только одно слово, и это не сработает. Я попытался изменить все %c на %s, но это мне не помогает. Я также понимаю, что ошибка сегментации - это указатель, указывающий куда-то не в память, но я не вижу, что с этим не так. Пожалуйста, помогите мне понять.

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

int main()
{
    char word[100];

    printf("Enter a sentence: ");
    scanf("%s", word);

    char *tok = strtok(word, " ");
    printf("%s\n", tok);

    while(tok != NULL)
    {
        tok = strtok(NULL, " ");
        printf("%s\n", tok);

        if(tok == NULL)
            printf("finished\n");
    }

    return 0;
}

РЕДАКТИРОВАТЬ: я изменил scanf("%s", word); to fgets(слово, 100, стандартный ввод); и теперь он печатает все, но я получаю ошибку сегментации.


person Anonymous    schedule 19.10.2017    source источник
comment
scanf("%s", word); не сохраняет пробелы в word, только "why". Используйте fgets().   -  person chux - Reinstate Monica    schedule 19.10.2017
comment
@chux спасибо, чувак, я изменил его на fgets (word, 100, stdin), но я все еще получаю ошибку сегментации.   -  person Anonymous    schedule 19.10.2017
comment
Подсказка. Почему код выполняет printf("%s\n", tok);, а затем проверяет наличие if(tok == NULL)...?   -  person chux - Reinstate Monica    schedule 19.10.2017
comment
Изменить наchar *tok = strtok(word, " \n"); while(tok != NULL) { printf("%s\n", tok); tok = strtok(NULL, " \n"); } printf("finished\n");   -  person BLUEPIXY    schedule 19.10.2017
comment
Я настоятельно рекомендую попробовать отладчик всякий раз, когда вы получаете ошибку сегментации. Обычно в этом случае где-то неожиданно оказывается указатель NULL, и отладчик позволяет быстро его найти.   -  person Mobius    schedule 19.10.2017


Ответы (2)


Как указано в комментариях, в вашем первом коде есть как минимум две проблемы.

  1. Не используйте scanf для чтения строки, которую вы хотите проанализировать. Вместо этого используйте fgets.

  2. Вы не проверяете, что tok не равно NULL перед его использованием (внутри цикла while)

Такие проблемы были бы легко обнаружены при отладке, поэтому я рекомендую вам прочитать как отлаживать небольшие программы

Исправленный код должен выглядеть так:

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

int main(void)
{
    char word[100];

    printf("Enter a sentence: ");
    /* read from stdin 
       note the `sizeof char`, if you need to change the size of `word`,
       you won't have to change this line. */
    fgets(word, sizeof word, stdin);

    /* initialize parser */
    char *tok = strtok(word, " ");

    while (tok != NULL)
    {
        /* printf token: it cannot be NULL here */
        printf("%s\n", tok);

        /* get next token*/
        tok = strtok(NULL, " ");
    }
    printf("finished\n");

    return 0;
}
person Community    schedule 19.10.2017
comment
Предложите объявить char *delim = " \n";, а затем char *tok = strtok(word, delim); (с аналогичными изменениями, используя везде delim). - person David C. Rankin; 19.10.2017

Этот код неверен

while(tok != NULL)
{
    tok = strtok(NULL, " ");
    printf("%s\n", tok);

    if(tok == NULL)
        printf("finished\n");
}

предположим, вы дошли до последнего прохода через цикл... он попадает в цикл, как и в прошлый раз.... поэтому вы делаете tok = strtok(NULL, " ");, который возвращает (и присваивает) NULL, так как больше ничего нет.... затем вы printf(3) это вызвали ошибку seg.

Просто измените это на это, чтобы вы не вошли в цикл, если больше нет доступных токенов.

while((tok = strtok(NULL, " ")) != NULL)
{
    printf("%s\n", tok);

    /* you don't touch tok inside the loop, so you don't need to
     * test it again once you get inside */
}

/* if(tok == NULL)  <-- you always have tok == NULL here */
printf("finished\n");

или проще

while(tok = strtok(NULL, " "))
{
    printf("%s\n", tok);
}
printf("finished\n");

Кроме того, добавьте \n ко второму параметру вызова strtok(3) (в двух вызовах, которые у вас есть в вашем списке, поскольку вы можете иметь только один токен, а окончание последней строки должно быть удалено из первого вызова), как при использовании fgets(3) обычно вы получите \n в конце строки (чего вы не хотите):

char *tok = strtok(word, " \n");
printf("%s\n", tok);

while(tok = strtok(NULL, " \n"))
{
    printf("%s\n", tok);
}
printf("finished\n");
person Luis Colorado    schedule 20.10.2017