2014-01-13 2 views
16

Я нашел этот пример программы, которая объясняет функцию strtok:Как работает функция strtok в C?

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

int main() 
{ 
    char str[] ="- This, a sample string."; 
    char * pch; 
    printf ("Splitting string \"%s\" into tokens:\n",str); 
    pch = strtok (str," ,.-"); 
    while (pch != NULL) 
    { 
     printf ("%s\n",pch); 
     pch = strtok (NULL, " ,.-"); 
    } 
    return 0; 
} 

Однако, я не вижу, как это можно работать.

Как возможно, что pch = strtok (NULL, " ,.-"); возвращает новый токен. Я имею в виду, мы звоним strtok с NULL. Это не имеет большого значения для меня.

+4

http://en.cppreference.com/w/c/string/byte/strtok –

+0

"* Я нашел эту программу-образец, которая объясняет функцию strtok *, это не пример, который объясняет, но документацию, поэтому вы можете читайте здесь: http://man7.org/linux/man-pages/man3/strtok.3.html – alk

+1

И это не имеет смысла никому .. поэтому был создан 'strtok_r()' ... – vrdhn

ответ

1

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

Из-за способа работы strtok вам необходимо убедиться, что вы используете многопоточную версию среды выполнения C, если вы пишете многопоточное приложение. Это гарантирует, что каждый поток получит свое собственное внутреннее состояние для strtok.

2

Функция strtok() хранит данные между вызовами. Он использует эти данные, когда вы вызываете его указателем NULL.

От http://www.cplusplus.com/reference/cstring/strtok/:

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

+1

Большинство современных сред выполнения хранят состояние в поточном локальном хранилище, что означает, что он является потокобезопасным, но не безопасным при повторном использовании. –

+0

Спасибо за исправление –

0

Функция strtok хранит данные во внутренней статической переменной, которая является общей для всех потоков.

Для безопасности потока следует использовать strtok_r

От http://www.opensource.apple.com/source/Libc/Libc-167/string.subproj/strtok.c

Посмотрите static char *last;

char * 
strtok(s, delim) 
    register char *s; 
    register const char *delim; 
{ 
    register char *spanp; 
    register int c, sc; 
    char *tok; 
    static char *last; 


    if (s == NULL && (s = last) == NULL) 
     return (NULL); 

    /* 
    * Skip (span) leading delimiters (s += strspn(s, delim), sort of). 
    */ 
cont: 
    c = *s++; 
    for (spanp = (char *)delim; (sc = *spanp++) != 0;) { 
     if (c == sc) 
      goto cont; 
    } 

    if (c == 0) {  /* no non-delimiter characters */ 
     last = NULL; 
     return (NULL); 
    } 
    tok = s - 1; 

    /* 
    * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). 
    * Note that delim must have one NUL; we stop if we see that, too. 
    */ 
    for (;;) { 
     c = *s++; 
     spanp = (char *)delim; 
     do { 
      if ((sc = *spanp++) == c) { 
       if (c == 0) 
        s = NULL; 
       else 
        s[-1] = 0; 
       last = s; 
       return (tok); 
      } 
     } while (sc != 0); 
    } 
    /* NOTREACHED */ 
} 
+0

' strtok_s' в Windows –

28

две вещи, чтобы знать о strtok. Как уже упоминалось, он «поддерживает внутреннее состояние». Кроме того, он испортил строку, которую вы ее подавали. По существу, он напишет '\0', где он найдет маркер, который вы предоставили, и возвращает указатель на начало строки. Внутренне он поддерживает расположение последнего токена; и в следующий раз, когда вы его назовете, он начнется оттуда.

Важным следствием является то, что вы не можете использовать strtok в строке типа const char* "hello world";, так как вы получите нарушение прав доступа при изменении содержимого строки const char*.

«Хорошая» вещь о strtok состоит в том, что она фактически не копирует строки - поэтому вам не нужно управлять дополнительным распределением памяти и т. Д. Но если вы не поймете вышеизложенное, вам будет сложно правильно его использовать.

Пример - если у вас есть «это, есть, строка», последовательные вызовы strtok будут генерировать указатели следующим образом (значение ^ - это возвращаемое значение).Обратите внимание, что добавляется '\0', где найдены токены; это означает, что исходная строка изменена:

t h i s , i s , a , s t r i n g \0   this,is,a,string 

t h i s \0 i s , a , s t r i n g \0   this 
^ 
t h i s \0 i s \0 a , s t r i n g \0   is 
      ^
t h i s \0 i s \0 a \0 s t r i n g \0   a 
         ^
t h i s \0 i s \0 a \0 s t r i n g \0   string 
          ^

Надеюсь, это имеет смысл.

Смежные вопросы