0Pricing
C Academy · Урок

strtok и разбор на токены

Разделяйте строки

«strtok и разбор на токены» — бесплатный урок C Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C Academy содержит 4 уроков всего.

Что такое токенизация

Токенизация — это разбиение строки на более мелкие части (токены), разделённые символами-разделителями.

Например, разбиение "a,b,c" по запятым даёт токены a, b и c. В C для этого предусмотрена функция strtok.

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

int main(void) {
    char text[] = "a,b,c";
    char *token = strtok(text, ",");
    printf("First token: %s\n", token);
    return 0;
}

Сигнатура strtok

char *strtok(char *str, const char *delim);

При первом вызове передайте строку. При последующих вызовах передавайте NULL, чтобы продолжить с места остановки. Функция возвращает следующий токен или NULL, когда токены закончились.

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

int main(void) {
    char text[] = "red green blue";
    char *tok = strtok(text, " ");
    while (tok != NULL) {
        printf("%s\n", tok);
        tok = strtok(NULL, " ");
    }
    return 0;
}

strtok изменяет строку

Важно: strtok изменяет исходную строку. Она заменяет каждый разделитель на '\0' и возвращает указатели на тот же буфер.

Поэтому нельзя токенизировать строковый литерал вроде "a,b", доступный только для чтения.

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

int main(void) {
    char data[] = "x:y:z";
    strtok(data, ":");
    printf("data[1] is now: %d (the null byte)\n", data[1]);
    return 0;
}

Создайте изменяемую копию

Поскольку strtok разрушает входные данные, сначала скопируйте строку, если исходная понадобится позже.

Используйте локальный массив char или скопируйте строку с помощью strcpy в буфер.

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

int main(void) {
    const char *original = "one-two-three";
    char copy[64];
    strcpy(copy, original);
    char *tok = strtok(copy, "-");
    while (tok) {
        printf("%s\n", tok);
        tok = strtok(NULL, "-");
    }
    printf("Original intact: %s\n", original);
    return 0;
}

Несколько разделителей

Аргумент delim представляет собой множество символов, а не последовательность. Любой символ из этого множества выступает разделителем.

Поэтому " ,;" одновременно разделяет по пробелам, запятым и точкам с запятой.

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

int main(void) {
    char text[] = "a,b;c d";
    char *tok = strtok(text, ",; ");
    while (tok) {
        printf("[%s]\n", tok);
        tok = strtok(NULL, ",; ");
    }
    return 0;
}

Идущие подряд разделители

strtok рассматривает последовательности разделителей как один разделитель и пропускает пустые токены.

Так, "a,,b" даёт только a и b, без пустого токена между ними. Помните об этом при разборе CSV, где пустые поля имеют значение.

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

int main(void) {
    char text[] = "a,,b";
    char *tok = strtok(text, ",");
    while (tok) {
        printf("token: %s\n", tok);
        tok = strtok(NULL, ",");
    }
    return 0;
}

Подсчёт токенов

Частая задача — подсчитать количество токенов в строке. Увеличивайте счётчик внутри цикла.

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

int main(void) {
    char sentence[] = "the quick brown fox";
    int count = 0;
    char *tok = strtok(sentence, " ");
    while (tok) {
        count++;
        tok = strtok(NULL, " ");
    }
    printf("Word count: %d\n", count);
    return 0;
}

strtok хранит скрытое состояние

strtok хранит свою позицию в статической внутренней переменной. Поэтому передача NULL позволяет продолжить обработку предыдущей строки.

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

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

int main(void) {
    char a[] = "1 2";
    char *t = strtok(a, " ");
    printf("%s\n", t);
    t = strtok(NULL, " ");
    printf("%s\n", t);
    return 0;
}

Сохранение токенов

Чтобы использовать токены после разбиения, сохраните возвращённые указатели в массиве. Они указывают на изменённый исходный буфер, который должен оставаться доступным.

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

int main(void) {
    char csv[] = "name,age,city";
    char *fields[10];
    int n = 0;
    char *tok = strtok(csv, ",");
    while (tok && n < 10) {
        fields[n++] = tok;
        tok = strtok(NULL, ",");
    }
    for (int i = 0; i < n; i++)
        printf("Field %d: %s\n", i, fields[i]);
    return 0;
}

Реентерабельная альтернатива

POSIX предоставляет strtok_r, которая принимает явный char **saveptr вместо скрытого состояния. Благодаря этому её безопасно вкладывать и использовать в разных потоках.

Для переносимого стандартного C обычная strtok подходит для разбора за один проход.

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

int main(void) {
    char text[] = "p:q:r";
    char *save;
    char *tok = strtok_r(text, ":", &save);
    while (tok) {
        printf("%s\n", tok);
        tok = strtok_r(NULL, ":", &save);
    }
    return 0;
}

Практика: разбиение пути

Токенизация особенно полезна при разборе структурированного текста, например путей к файлам. Разбиение по / позволяет получить каждый компонент пути.

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

int main(void) {
    char path[] = "usr/local/bin";
    char *part = strtok(path, "/");
    while (part) {
        printf("-> %s\n", part);
        part = strtok(NULL, "/");
    }
    return 0;
}

Быстрая проверка

Проверьте, насколько хорошо Вы понимаете работу strtok.

Итоги

Вы научились разделять строки с помощью strtok:

  • При первом вызове передаётся строка, при последующих — NULL.
  • Функция изменяет ввод, заменяя разделители на '\0'; сначала копируйте строки, доступные только для чтения.
  • Аргумент-разделитель является множеством; последовательные разделители объединяются.
  • Функция использует статическое состояние и не является потокобезопасной; при необходимости используйте strtok_r.

Часто задаваемые вопросы

Урок «strtok и разбор на токены» бесплатный?

Да — полный текст урока «strtok и разбор на токены» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C Academy, подпишись на CoddyKit PRO. Курс C Academy содержит 4 уроков всего.

Чему я научусь в уроке «strtok и разбор на токены»?

Разделяйте строки Ты практикуешь C Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C Academy?

Предыдущий опыт не требуется. C Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «strtok и разбор на токены»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C Academy?

Да. Каждый урок C Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. strlen, strcpy, strcat
  2. strcmp и сравнение
  3. strtok и разбор на токены
  4. memcpy и memset
← Назад к C Academy