Menu
Jest wolny
rejestracja
Dom  /  Problemy/ Opis Strtoka. Man strtok_r (3): pobieranie elementów (tokenów) z ciągu

Opis Strtoka. Man strtok_r (3): pobieranie elementów (tokenów) z ciągu

4 odpowiedzi

Dwie rzeczy, które warto wiedzieć o strtoku. Jak wspomniano, „utrzymuje stan wewnętrzny”. Co więcej, on zepsułeś linię, którą ją karmisz... Zasadniczo napisze "\ 0", gdzie znajdzie podany przez Ciebie znacznik i zwróci wskaźnik na początek linii. Wewnętrznie utrzymuje lokalizację ostatniego tokena; a następnym razem, gdy to nazwiesz, zacznie się od tego miejsca.

Ważnym następstwem jest to, że nie możesz użyć strtok na const char * "hello world"; ponieważ otrzymasz naruszenie zasad dostępu, gdy zmienisz zawartość ciągu const char *.

„Dobrą rzeczą” w strtok jest to, że w rzeczywistości nie kopiuje on ciągów, więc nie musisz zarządzać dodatkowymi alokacjami pamięci itp. Ale jeśli nie zrozumiesz powyższego, będziesz miał problemy z jego używaniem.

Przykład. Jeśli masz "this, is, a string", kolejne wywołania strtok wygenerują takie wskaźniki (wartość ^ jest wartością zwracaną). Zauważ, że "\ 0" jest dodawany w miejscu znalezienia tokenów; to znaczy, że ciąg źródłowy zmieniono:

To is, a, string \ 0 this, is, a, string this \ 0 is, a, string \ 0 this ^ this \ 0 is \ 0 a, string \ 0 is ^ this \ 0 is \ 0 a \ 0 string \ 0 a ^ to \ 0 to \ 0 a \ 0 string \ 0 string ^

Mam nadzieję, że to ma sens.

Funkcja strtok() przechowuje dane między połączeniami. Używa tych danych, gdy wywołujesz je ze wskaźnikiem NULL.

Punkt, w którym znaleziono ostatni token, jest przechowywany wewnętrznie przez funkcję, która zostanie użyta przy następnym wywołaniu (nie jest wymagana implementacja specyficzna dla biblioteki, aby zapobiec błędom danych).

strtok utrzymuje stan wewnętrzny. Kiedy wywołujesz go z wartością inną niż NULL, inicjuje się ponownie, aby użyć podanego ciągu. Kiedy wywołujesz go z NULL, używa tego ciągu i dowolnego innego stanu, który aktualnie otrzymuje, aby zwrócić następny token.

Ze względu na to, jak działa strtok, musisz upewnić się, że łączysz się z wielowątkową wersją środowiska wykonawczego C, jeśli piszesz aplikacja wielowątkowa... Zapewnia to, że każdy wątek ma swój własny stan wewnętrzny dla strtok.

Funkcja strtok przechowuje dane w wewnętrznej zmiennej statycznej, która jest współużytkowana przez wszystkie wątki.

Aby zapewnić bezpieczeństwo wątków, musisz użyć strtok_r

Spójrz na static char * last;

Char * strtok (s, delim) zarejestruj char * s; zarejestruj const char * delim; (rejestr znak * spanp; register int c, sc; char * tok; znak statyczny * last; if (s == NULL && (s = last) == NULL) return (NULL); / * * Pomiń (span) wiodące ograniczniki (s + = strspn (s, delim), sort of). * / cont: c = * s ++; for (spanp = (char *) delim; (sc = * spanp ++)! = 0;) (if (c == sc) goto cont;) if (c == 0) (/ * bez znaków nieograniczających * / last = NULL; return (NULL);) tok = s - 1; / * * Token skanowania (skanuj w poszukiwaniu ograniczników : s + = strcspn (s, delim), rodzaj). * Zauważ, że delim musi mieć jedną wartość NUL; zatrzymujemy się, jeśli również to widzimy. * / 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);) / * NIE DOTYCZY * /)

dzielić się

#włączać znak * strtok (znak * str1, const znak * str2);

Funkcja strtok() zwraca wskaźnik do następnego tokena w ciągu wskazywanym przez parametr str1... Znaki tworzące łańcuch adresowany przez parametr str2, są ogranicznikami, które definiują token. Jeśli nie ma tokena do zwrócenia, zwracany jest wskaźnik o wartości null.

W wersji C99 do parametrów str1 oraz str2 zastosowano kwalifikator ograniczenia.

Aby podzielić jakiś ciąg na tokeny, przy pierwszym wywołaniu funkcji strtok() parametr str1 powinien wskazywać na początek tej linii. Przy kolejnych wywołaniach funkcji jako parametru str1 musisz użyć wskaźnika zerowego. W ten sposób cała linia zostaje podzielona na żetony.

Za każdym razem, gdy wywoływana jest funkcja strtok(), możesz użyć różne zestawy separatory.

Przykład

Ten program przełamuje linię „Trawa jest zielona, ​​słońce świeci” na żetony oddzielone spacjami i przecinkami. Rezultatem będzie

Trawa | zielony | słońce | błyszczy #include #włączać int main (void) (char * p; p = strtok ("Trawa zmienia kolor na zielony, słońce świeci", ""); printf (p); do (p = strtok ("\ 0", ","); if (p ) printf ("|% s", p);) while (p); return 0;)

Składnia:

#włączać
char * strtok (znak * str, const char * wrz);

Argumenty:

str jest wskaźnikiem do łańcucha do podziału.
sep jest wskaźnikiem do łańcucha zawierającego zestaw znaków separatora.

Zwracana wartość:

NULL – jeśli string nie może być podzielony na części.
Wskaźnik do pierwszego znaku wybranej części ciągu.

Opis:

Funkcja strtok wybiera następną część ciągu wskazywanego przez argument str, oddzieloną jednym ze znaków separatora określonych w ciągu wskazywanym przez argument sep. Sekwencyjne wywołanie funkcji strtok powoduje podzielenie ciągu str na części (tokeny).

„Pierwsze wywołanie funkcji strtok określa początek oddzielonego ciągu (str) i początek ciągu zawierającego separatory (sep). Po pierwsze, funkcja strtok iteruje przez znaki w str i szuka znaku, który nie jest zawarty w ciągu separatora sep. Jeśli znak końca wiersza zostanie napotkany w str przed znalezieniem znaku nieuwzględnionego w sep, wówczas str nie może zostać podzielony na części i zwracany jest wskaźnik null (NULL). Jeśli taki znak zostanie znaleziony, jest uważany za początek pierwszej części ciągu str. "

Następnie funkcja strtok wyszukuje separator, czyli znak zawarty w ciągu sep. Jeśli taki znak nie zostanie znaleziony, uważa się, że łańcuch str składa się z jednej części, a późniejsze rozdzielenie łańcucha str zwróci wskaźnik zerowy. Jeśli taki symbol zostanie znaleziony. następnie jest zastępowany znakiem null (znakiem końca wiersza). Następnie funkcja strtok zapamiętuje bieżącą pozycję (wskaźnik do znaku, od którego rozpocznie się wyszukiwanie następnej części ciągu) i zwraca wskaźnik do początku pierwszej wybranej części ciągu.

Jeśli funkcja strtok zwróciła wskaźnik inny niż null, możesz kontynuować dzielenie str na części. Aby kontynuować dzielenie łańcucha, ponownie wywoływana jest funkcja strtok, ale zamiast wskaźnika do łańcucha, który ma zostać rozdzielony, jako pierwsze rozszerzenie podaje się NULL. W takim przypadku funkcja strtok będzie kontynuowała oddzielanie od zapamiętanego adresu. Algorytm partycjonowania pozostaje taki sam.

Przykład:

W tym przykładzie ciąg „test1 / test2 / test3 / test4” jest dzielony na części przez separator „/” za pomocą funkcji strtok. Wynik dzielenia jest wyprowadzany do konsoli.

Wynik:

Wyjście konsoli:


char daleko * daleko _fstrtok (const char daleko * str1, const char daleko * str2)

Opis:

Funkcja strtok() zwraca wskaźnik do następnego tokena w ciągu wskazywanym przez str1. Znaki z łańcucha wskazywanego przez str2 są używane jako ograniczniki do zdefiniowania tokenu. Jeśli token nie zostanie znaleziony, zwracana jest wartość NULL.

Pierwsze wywołanie strtok() faktycznie używa str1 jako wskaźnika. Kolejne wywołania używają NULL jako pierwszego argumentu. W ten sposób cała linia może zostać ztokenizowana.

Ważne jest, aby zrozumieć, że funkcja strtok() modyfikuje ciąg znaków wskazywany przez str1. Za każdym razem, gdy zostanie znaleziony token, w miejscu, w którym znaleziono ogranicznik, umieszczany jest znak null. W ten sposób strtok() jest przesuwany wzdłuż linii.

Za każdym razem, gdy wywołujesz strtok(), możesz zmienić zestaw ograniczników.

Funkcja _fstrtok () jest wersją FAR danej funkcji.

Poniższy program dzieli ciąg „Żołnierz letni, słoneczny patriota” na żetony, używając spacji i przecinków jako ograniczników. W wyniku działania programu zostanie wygenerowany wiersz o następującej postaci: „The | lato | żołnierz | | słońce | patriota”.
#włączać
#włączać
int główny (unieważniony)
{
znak * p;
p = strtok ( „Letni żołnierz, słoneczny patriota”, " " ) ;
printf (p);
robić (
p = strtok (" \0 " , ", " ) ;
if (p) printf ("|% s", p);
) podczas (p);
zwróć 0;
}

Inny alias

strtok

PRZEGLĄD

#włączać

znak * strtok (znak *str, const znak *delim);
znak * strtok_r (znak *str, const znak *delim, znak **zapisz);

Wymagania makr testu właściwości dla glibc (patrz str. Feature_test_macros(7)):

strtok_r(): _SVID_SOURCE || _BSD_SOURCE || _POSIX_C_SOURCE> = 1 || _XOPEN_SOURCE || _POSIX_SOURCE

OPIS

Funkcjonować strtok() dzieli ciąg na sekwencję zerową lub większą liczbą niepustych tokenów. Na pierwszy telefon strtok() przeanalizowany ciąg musi być określony w argumencie str... W każdym kolejnym wywołaniu analizującym ten sam ciąg, wartość str musi być NULL.

W argumentacji delim określony jest zestaw bajtów, które są uważane za separatory tokenów w analizowanym ciągu. Dzwoniący może określić różne linie w delim w kolejnych wywołaniach podczas analizowania tego samego ciągu.

Każdy telefon strtok() zwraca wskaźnik do łańcucha zakończonego znakiem null, który zawiera następny token. Ten wiersz nie zawiera bajtu ogranicznika. Jeśli nie ma więcej żetonów, to strtok() zwraca NULL.

Sekwencja połączeń strtok(), operując na pojedynczym łańcuchu, utrzymuje wskaźnik definiujący punkt, w którym należy rozpocząć szukanie następnego tokena. Pierwsze połączenie strtok() przypisuje temu wskaźnikowi odwołanie do pierwszego bajtu ciągu. Początek następnego żetonu określa się, wyszukując do przodu w str następny bajt nie jest ogranicznikiem. Jeśli zostanie znaleziony bajt, to jest on traktowany jako początek następnego tokena. Jeśli nie zostanie znaleziony taki bajt, nie ma więcej tokenów i strtok() zwraca NULL (dla łańcucha pustego lub składającego się tylko z ograniczników w tym przypadku NULL zostanie zwrócony przy pierwszym wywołaniu strtok()).

Koniec każdego tokenu jest przeszukiwany do przodu, aż zostanie znaleziony bajt ogranicznika lub kończący bajt null ("\ 0"). Jeśli zostanie znaleziony bajt ogranicznika, zostanie on zastąpiony bajtem zerowym, aby zakończyć bieżący token, a strtok() przechowuje wskaźnik do następnego bajtu; ten wskaźnik będzie używany jako punkt wyjścia podczas szukania następnego tokena. W tym przypadku strtok() zwraca wskaźnik na początek znalezionego tokena.

Z powyższego opisu wynika, że ​​sekwencja dwóch lub więcej sąsiadujących ze sobą bajtów separatora w skanowanym wierszu jest uważana za jeden separator, a bajty separatora na początku lub na końcu wiersza są ignorowane. Innymi słowy, żetony zwrócone strtok() są zawsze niepustymi wierszami. To znaczy na przykład, jeśli jest linia „ aaa ;; bbb,", potem kolejne telefony strtok() z określonymi separatorami wierszy " ;, "Oddałbym linie" aaa" oraz " bbb„Po którym następuje wskaźnik zerowy.

Funkcjonować strtok_r() to wersja reentrant strtok(). Argument zapisz jest wskaźnikiem do zmiennej znak * który jest używany wewnętrznie strtok_r(), aby pamiętać o kontekście między kolejnymi wywołaniami podczas analizowania tego samego ciągu.

Na pierwszy telefon strtok_r() oznaczający str powinien wskazywać na ciąg do przeanalizowania, a wartość zapisz ignorowane. Przy kolejnych wezwaniach wartość str musi być NULL, a wartość zapisz nie powinno się zmienić od poprzedniego połączenia.

Różne ciągi mogą być analizowane w tym samym czasie za pomocą wielu przebiegów strtok_r() z różnymi argumentami zapisz.

WARTOŚĆ ZWROTU

Funkcje strtok() oraz strtok_r() zwraca wskaźnik do następnego tokena lub NULL, jeśli nie ma więcej tokenów.

ATRYBUTY

Aby zapoznać się z opisem terminów w tej sekcji, zobacz atrybuty(7).
Berło Atrybut Oznaczający
strtok() nieszkodliwość w wątkachniebezpieczne (wyścig MT-niebezpieczny: strtok)
strtok_r() nieszkodliwość w wątkachnieszkodliwy (MT-Safe)

ZGODNOŚĆ

strtok() POSIX.1-2001, POSIX.1-2008, C89, C99, SVr4, 4.3BSD. strtok_r() POSIX.1-2001, POSIX.1-2008.

WADY

Używaj tych funkcji ostrożnie. Zauważ, że: * Te funkcje modyfikują swój pierwszy argument. * Tych funkcji nie można używać ze stałymi ciągami. * Utracono tożsamość bajtu ogranicznika. * Podczas analizowania funkcji strtok() używa bufora statycznego, więc nie jest bezpieczny wątkowo. Posługiwać się strtok_r() w tym przypadku.

PRZYKŁAD

Poniższy program używa zagnieżdżonych pętli, które wywołują strtok_r(), aby podzielić ciąg na jego składowe tokeny. W pierwszym parametrze wiersz poleceń analizowany ciąg jest określony. Drugi parametr określa bajt(y) - separator używany do dzielenia ciągu na "złożone" tokeny. Trzeci parametr określa bajt(y) - separator używany do rozdzielania tokenów „złożonych” na subtokeny.

Przykładowy wynik programu:

$./a.out "a / bbb /// cc; xxx: rrrr:" ":;" „/” 1: a / bbb /// cc -> a -> bbb -> cc 2: xxx -> xxx 3: rrrr -> rrrr

Kod źródłowy programu

#włączać #włączać #włączać int main (int argc, char * argv) (char * str1, * str2, * token, * subtoken; char * saveptr1, * saveptr2; int j; if (argc! = 4) (fprintf (stderr, "Usage:% s string delim subdelim \ n ", argv); exit (EXIT_FAILURE);) for (j = 1, str1 = argv;; j ++, str1 = NULL) (token = strtok_r (str1, argv, & saveptr1); if (token = = NULL) break; printf ("% d:% s \ n", j, token); for (str2 = token;; str2 = NULL) (subtoken = strtok_r (str2, argv, & saveptr2); jeśli (subtoken == NULL) break; printf ("->% s \ n", subtoken);)) exit (EXIT_SUCCESS);)

Kolejny przykład programu używającego strtok() może być znaleziony w getaddrinfo_a(3).