Взятие последнего слова в строке с strtok - PullRequest
0 голосов
/ 28 июня 2018

Дан файл со следующей строкой:

слово1 слово2 слово3 слово4

Я пытался написать следующий код:

FILE* f = fopen("my_file.txt", "r");
char line[MAX_BUFFER + 1];
if (fgets(line, MAX_LENGTH_LINE, f) == NULL) {
    return NULL;
}
char* word = strtok(line, " ");
for (int i = 0; i < 4; i++) {
    printf("%s ", word);
    word = strtok(NULL, " ");
}

Для печати «слова».

Это работает. Но я чего-то не понимаю.

Как оно достигает последнего слова word4? (Я не понимаю, потому что после слова "word4" не существует пробела) ..

Ответы [ 2 ]

0 голосов
/ 28 июня 2018

Ваш код не проверяет возвращаемое значение strtok(), в некоторых случаях это может быть небезопасно.

/*  Split string
    @content origin string content
    @delim   delimiter for splitting
    @psize   pointer pointing at the variable to store token size
    @return  tokens after splitting
 */
const char **split(char *content, const char *delim, int *psize)
{
    char *token;
    const char **tokens;
    int capacity;
    int size = 0;

    token = strtok(content, delim);
    if (!token)
    {
        return NULL;
    }

    // Initialize tokens
    tokens = malloc(sizeof(char *) * 64);
    if (!tokens)
    {
        exit(-1);
    }
    capacity = 64;

    tokens[size++] = token;

    while ((token = strtok(NULL, delim)))
    {
        if (size >= capacity)
        {
            tokens = realloc(tokens, sizeof(char *) * capacity * 2);
            if (!tokens)
            {
                exit(-1);
            }
            capacity *= 2;
        }
        tokens[size++] = token;
    }

    // if (size < capacity)
    // {
    //  tokens = realloc(tokens, sizeof(char *) * size);
    //  if (!tokens)
    //  {
    //      exit(-1);
    //  }
    // }
    *psize = size;

    return tokens;
}
0 голосов
/ 28 июня 2018

Я не совсем уверен, что вы спрашиваете. Вы спрашиваете, как программа смогла правильно прочитать word4 из файла, даже если за ним не было пробела? Или вы спрашиваете, почему, когда программа выводила word4 назад, после нее, казалось, не было пробела?

Ответ на первый вопрос заключается в том, что strtok предназначен для предоставления вам токенов , разделенных разделителями, а не , оканчивающимися разделителями. Не требуется, чтобы за последним токеном следовал разделитель.

Чтобы увидеть ответ на второй вопрос, может быть более понятным, если мы немного скорректируем программу и ее распечатку:

char* word = strtok(line, " ");
for (int i = 0; word != NULL; i++) {
    printf("%d: \"%s\"\n", i, word);
    word = strtok(NULL, " ");
}

Я сделал два изменения здесь:

  1. Цикл выполняется до тех пор, пока word не станет NULL, то есть, пока strtok не найдет другое слово в строке. (Это делается для того, чтобы убедиться, что мы видим все слова, и чтобы мы не пытались обрабатывать четвертое слово специально каким-либо образом. Если вы были , пытаясь обработать четвертое слово специально каким-то образом, скажите, пожалуйста.)
  2. Слова выводятся обратно в окружении кавычек, чтобы мы могли точно видеть, что они содержат.

Когда я запускаю измененную программу, я вижу:

0: "word1"
1: "word2"
2: "word3"
3: "word4
"

Эта последняя строка поначалу выглядит очень странно, но объяснение простое. Изначально вы читаете строку, используя fgets, который копирует завершающий символ \n в буфер line. Таким образом, в итоге он остается прикрепленным к word4; то есть четвертое «слово» - "word4\n".

По этой причине часто хорошей идеей является включение \n в набор символов разделителей пробелов, которые вы передаете strtok - то есть вместо этого вы можете вызвать strtok(line, " \n"). Если я сделаю это (в обоих вызовах strtok), выход изменится на

0: "word1"
1: "word2"
2: "word3"
3: "word4"

, что может быть ближе к тому, что вы ожидали.

...