Okna.  Wirusy.  Notatniki.  Internet.  biuro.  Narzędzia.  Kierowcy

Inne pseudonimy

strtok

RECENZJA

#włączać

znak *strtok(znak *ul, stały znak *delim);
znak *strtok_r(znak *ul, stały znak *delim, znak **zapisz);

Wymagania makrotestu właściwości dla glibc (patrz makra_testowe_funkcji(7)):

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

OPIS

Funkcjonować strtok() dzieli ciąg znaków na sekwencję zerową lub więcej niepustych tokenów. Przy pierwszym wezwaniu strtok() analizowany łańcuch musi być określony w argumencie ul. W każdym kolejnym wywołaniu, które analizuje ten sam ciąg, wartość ul musi być NULL.

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

Każde wezwanie strtok() zwraca wskaźnik do łańcucha zakończonego znakiem null, który zawiera następny token. Ten ciąg nie zawiera bajtu ogranicznika. Jeśli nie ma już żetonów, to strtok() zwraca NULL.

Sekwencja połączeń strtok(), które operują na pojedynczym łańcuchu, utrzymują wskaźnik określający punkt, w którym należy rozpocząć wyszukiwanie następnego tokena. Pierwsze połączenie strtok() przypisuje temu wskaźnikowi odwołanie do pierwszego bajtu łańcucha. Początek następnego żetonu jest określany przez wyszukiwanie w przód ul następny bajt nie jest ogranicznikiem. Jeśli zostanie znaleziony bajt, jest on traktowany jako początek następnego tokena. Jeśli nie zostanie znaleziony taki bajt, oznacza to, że nie ma już tokenów i strtok() zwraca NULL (dla ciągu pustego lub składającego się tylko z ograniczników w tym przypadku NULL zostanie zwrócone przy pierwszym wywołaniu strtok()).

Koniec każdego tokenu jest znajdowany przez wyszukiwanie w przód trwające do momentu znalezienia bajtu ogranicznika lub kończącego bajtu zerowego („\0”). Jeśli zostanie znaleziony bajt ogranicznika, jest on zastępowany bajtem zerowym, aby zakończyć bieżący token i strtok() przechowuje wskaźnik do następnego bajtu; ten wskaźnik będzie używany jako punkt początkowy podczas wyszukiwania następnego tokena. W tym przypadku strtok() zwraca wskaźnik do początku znalezionego tokena.

Z powyższego opisu wynika, że ​​sekwencja dwóch lub więcej sąsiadujących ze sobą bajtów separatora w zeskanowanym łańcuchu jest traktowana jako pojedynczy separator, a bajty separatora na początku lub na końcu łańcucha są ignorowane. Innymi słowy, tokeny wróciły strtok() - zawsze nie puste linie. To znaczy, na przykład, jeśli istnieje linia „ aaa;;bbb,”, a następnie kolejne połączenia strtok() z określonymi separatorami wierszy " ;, 'zwróci ciągi znaków' aaa" I " 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ątrz strtok_r(), aby uwzględnić kontekst między kolejnymi wywołaniami podczas analizowania tego samego ciągu.

Przy pierwszym wezwaniu strtok_r() oznaczający ul musi wskazywać na przeanalizowany ciąg i wartość zapisz ignorowane. W kolejnych wywołaniach wartość ul musi mieć wartość NULL i wartość zapisz nie mógł się zmienić od poprzedniego wezwania.

Wiele łańcuchów może być analizowanych jednocześnie w wielu przebiegach strtok_r() z różnymi argumentami zapisz.

WARTOŚĆ ZWRACANA

Funkcje strtok() I 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).
Interfejs Atrybut Oznaczający
strtok() nieszkodliwość w niciachniebezpieczny (MT-niebezpieczny wyścig: strtok)
strtok_r() nieszkodliwość w niciachnieszkodliwy (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 z rozwagą. Zauważ, że: * Te funkcje zmieniają swój pierwszy argument. * Te funkcje nie mogą być używane ze stałymi łańcuchami. * Tożsamość bajtu ogranicznika została utracona. * Podczas analizy funkcji strtok() używa bufora statycznego, więc nie jest bezpieczny dla wątków. Używać 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ć łańcuch na tokeny składowe. W pierwszym parametrze wiersz poleceń podany jest ciąg do przeanalizowania. Drugi parametr określa bajt(y) ogranicznika, który jest używany do dzielenia łańcucha na tokeny „złożone”. Trzeci parametr określa bajty separatora, które są używane do rozdzielania tokenów „złożonych” na podtokeny.

Przykład wyjścia programu:

$./a.out "a/bbb///cc;xxx:yyy:" ":;" "/" 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, "Użycie: % 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); if (subtoken == NULL) break; printf(" --> %s\n", subtoken); ) ) exit(EXIT_SUCCESS); )

Inny przykład użycia programu strtok() może być znaleziony w getaddrinfo_a(3).

4 odpowiedzi

Dwie rzeczy, które warto wiedzieć o strtok . Jak wspomniano, „utrzymuje stan wewnętrzny”. Ponadto on zepsuł kolejkę, którą ją karmisz. Zasadniczo napisze „\ 0”, gdzie znajdzie podany znacznik i zwróci wskaźnik na początek łańcucha. Wewnętrznie zachowuje lokalizację ostatniego tokena; a następnym razem, gdy go wywołasz, zacznie się od tego miejsca.

Ważną konsekwencją jest to, że nie można użyć strtok na łańcuchu, takim jak const char* "hello world"; , ponieważ podczas zmiany zawartości ciągu znaków const char* wystąpi naruszenie zasad dostępu.

„Miłą rzeczą” strtok jest to, że tak naprawdę nie kopiuje łańcuchów, więc nie musisz zarządzać dodatkową alokacją pamięci itp. Ale jeśli nie rozumiesz powyższego, będziesz miał problemy z używaniem go.

Przykład. Jeśli masz „to, jest, łańcuch”, kolejne wywołania strtok będą generować wskaźniki w następujący sposób (wartość ^ jest wartością zwracaną). Zauważ, że tam, gdzie znajdują się tokeny, dodawane jest „\0”; oznacza to, że oryginalna linia została zmieniona:

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

Mam nadzieję, że to ma sens.

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

Punkt, w którym znaleziono ostatni token, jest przechowywany wewnętrznie z funkcją do użycia przy następnym wywołaniu (nie jest wymagana żadna konkretna implementacja biblioteki, aby zapobiec awariom danych).

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

Ze względu na sposób działania strtok musisz upewnić się, że łączysz się z wielowątkową wersją środowiska wykonawczego C, jeśli piszesz aplikację wielowątkową. Gwarantuje to, że każdy wątek otrzyma swój własny stan wewnętrzny dla strtok .

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

Dla bezpieczeństwa wątków powinieneś użyć strtok_r

Spójrz na static char *last;

Char * strtok(s, delim) register char *s; zarejestruj const char *delim; ( register char *spanp; register int c, sc; char *tok; static char *last; if (s == NULL && (s = last) == NULL) return (NULL); /* * Pomiń (span) początek 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) ( /* brak znaków innych niż ograniczniki */ last = NULL; return (NULL); ) tok = s - 1; /* * Token skanowania (skanowanie w poszukiwaniu ograniczników : s += strcspn(s, delim), rodzaj). *)delim; do ( if ((sc = *spanp++) == c) ( if (c == 0) s = NULL; else s[-1] = 0; last = s; return (tok); ) ) while (sc != 0); ) /* NIEDOKONANO */ )

udział

Funkcja strtok() zwraca wskaźnik do następnego tokena w łańcuchu wskazywanym przez parametr str1. Znaki składające się na ciąg adresowany przez parametr str2 są ogranicznikami definiującymi token. Jeśli nie ma tokenu do zwrócenia, zwracany jest wskaźnik zerowy.

W wersji C99 kwalifikator ograniczenia jest stosowany do parametrów str1 i str2.

Aby podzielić ciąg na tokeny, przy pierwszym wywołaniu funkcji strtok() parametr str1 musi wskazywać początek tego ciągu. W kolejnych wywołaniach funkcji jako parametr str1 musi być użyty wskaźnik zerowy. W takim przypadku cały ciąg będzie aktualizowany przy każdym wywołaniu funkcji.

Każde wywołanie funkcji strtok() może używać innego zestawu separatorów tokenów.

Funkcja strtok() umożliwia zredukowanie łańcucha do jego części składowych. Na przykład poniższy program tokenizuje ciąg „Jeden, dwa i trzy”.

#włączać #włączać int main(void) char *p; p = strtok("Jeden, dwa i trzy.", ","); printf(p); do (p = strtok(NULL, ",. "); if(p) printf("|%s", p); ) while(p), zwróć 0; )

Wyjście tego programu jest następujące.

jeden | dwa | i | trzy

Zwróć uwagę, że funkcja strtok() jest najpierw wywoływana z oryginalnym ciągiem znaków, ale kolejne wywołania używają NULL jako pierwszego argumentu. Funkcja strtok() utrzymuje wewnętrzny wskaźnik do łańcucha znaków, który ma zostać przetworzony. Jeśli pierwszy argument funkcji strtok() wskazuje na łańcuch, wewnętrzny wskaźnik jest ustawiany na początek tego ciągu. Jeśli pierwszy argument jest równa wartości NULL funkcja strtok() kontynuuje przetwarzanie poprzedniego wiersza, zaczynając od pozycji zapisanej w poprzednim kroku, i przesuwa wewnętrzny wskaźnik w miarę odbierania następnego tokenu. Zatem funkcja strtok() „przechodzi” przez cały łańcuch. Zwróć również uwagę, jak zmienia się łańcuch ograniczników przy pierwszym i kolejnych wywołaniach funkcji. Ograniczniki można definiować inaczej w każdym wywołaniu.

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

Opis:

Funkcja strtok() zwraca wskaźnik do następnego tokenu w łańcuchu wskazywanym przez str1. Znaki z łańcucha wskazywanego przez str2 są używane jako ograniczniki definiujące token. 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ły łańcuch może być tokenizowany.

Ważne jest, aby zrozumieć, że funkcja strtok() modyfikuje łańcuch wskazywany przez str1. Za każdym razem, gdy zostanie znaleziony token, w miejscu, w którym znaleziono ogranicznik, umieszczany jest znak null. Tak więc strtok() przesuwa się wzdłuż łańcucha.

Przy każdym wywołaniu strtok() możesz zmienić zestaw ograniczników.

Funkcja _fstrtok() jest wersją FAR danej funkcji.

Poniższy program tokenizuje ciąg „Letni żołnierz, słoneczny patriota”, używając spacji i przecinków jako ograniczników. W wyniku działania programu zostanie wygenerowana linia o następującej postaci: „The | lato | żołnierze | | słońce | patriota".
#włączać
#włączać
int główny (pusty)
{
znak*p;
p = strtok( „Letni żołnierz, słoneczny patriota”, " " ) ;
printf(p);
Do(
p=strtok(" \0 " , ", " ) ;
if (p) printf("|%s" , p) ;
) natomiast (p);
powrót 0 ;
}

Języki programowania mogą obejmować funkcje specjalne do pracy z ciągami znaków, oszczędzając w ten sposób programiście konieczności pisania własnych funkcji przetwarzania łańcuchów. Na przykład często konieczne jest określenie długości łańcucha, dlatego języki udostępniają funkcję pomiaru jego długości.

W języku programowania C funkcje do pracy z ciągami znaków są deklarowane w pliku nagłówkowym string.h, o czym należy pamiętać, aby umieścić go w kodzie źródłowym. Istnieje około dwudziestu funkcji do pracy z ciągami znaków. Wśród nich są takie, które wyszukują znaki w ciągu znaków, funkcje porównujące, kopiujące ciąg znaków, a także bardziej szczegółowe. Lista i opis większości istniejących ten moment w języku C funkcje można znaleźć w dodatku do książki B. Kernighana, D. Ritchiego „The C Programming Language. Second Edition”.

Wszystkie funkcje zadeklarowane w string.h mogą, ale nie muszą, modyfikować jeden z łańcuchów przekazywanych przez wskaźnik w trakcie swojej pracy. To zależy od celu funkcji. Jednak większość z nich coś zwraca: albo wskaźnik do znaku, albo liczbę całkowitą. Co więcej, jeśli funkcja zmieni jeden ze swoich parametrów i została w tym celu wywołana, to to, co zwraca, można zignorować (to znaczy nie przypisać do niczego w funkcji wywołującej).

Na przykład funkcja strcpy() ma następującą deklarację: char *strcpy (char *, const char*) . Kopiuje ciąg wskazywany przez drugi parametr do ciągu wskazywanego przez pierwszy parametr. Tak więc pierwszy parametr jest zmieniony. Dodatkowo funkcja zwraca wskaźnik do pierwszego znaku łańcucha:

znak s1[10], s2[10]; znak*s3; s3 = s2; dostaje (s1); s3 = strcpy (s2, s1) ; stawia (s2); stawia (s3) ; printf("%p,%p \N", s2, s3);

Tutaj s2 i s3 wskazują na ten sam znak (printf() zwraca ten sam adres). Jednak to, co strcpy() zwraca, nie może być przypisane do tablicy. Wynik tej funkcji zwykle nie jest do niczego przypisany; czasami wystarczy, że po prostu zmieni jeden z ciągów przekazywanych przez wskaźnik.

Kolejną rzeczą są funkcje takie jak strlen() czy strcmp() , które nie zmieniają parametrów, ale są wywoływane ze względu na wynik. Funkcja strcmp() porównuje dwa łańcuchy argumentów litera po literze (leksykograficznie) i zwraca 0, -1 lub 1. Na przykład wywołanie strcmp("chłopiec", "ciało") zwróci 1, ponieważ kod literowy „y” więcej niż list"D". Wywołanie strcmp("body", "boy") zwróci -1, ponieważ pierwszy argument jest leksykograficznie mniejszy niż drugi.

funkcja strtok().

Za pomocą funkcji strtok() możesz podzielić ciąg znaków na osobne części (tokeny). Deklaracja tej funkcji wygląda tak: char *strtok (char *, const char *) . Przy pierwszym wywołaniu funkcji pierwszym parametrem jest łańcuch do podziału. Drugi parametr określa ciąg separatora. Przy kolejnych wywołaniach funkcji dla tego samego wiersza pierwszy parametr musi mieć wartość NULL, ponieważ funkcja już „zapamiętała”, z czym współpracuje. Rozważ przykład:

char str = "jeden, dwa, trzy, cztery, pięć" ; znak*sp; sp = strtok (str, ", " ); while (sp) ( stawia (sp) ; sp = strtok (NULL, ", " ) ; )

W wyniku wykonania tego kodu w kolumnie wyświetlane są następujące słowa:

jeden dwa trzy cztery pięć

Przy pierwszym wywołaniu metody strtok() funkcja otrzymuje wskaźnik do pierwszego znaku tablicy i łańcuch separatora. Po tym wywołaniu tablica str zostaje zmieniona, pozostaje w niej tylko słowo „jeden”, a funkcja zwraca również wskaźnik do tego słowa, który jest przypisany do sp.

Chociaż straciliśmy resztę tablicy w funkcji wywołującej, wskaźnik do pozostałej części tablicy jest zachowany wewnątrz strtok(). Po przekazaniu NULL funkcja „wie”, że ma pracować z tym ogonem.

Kopiowanie części napisów

Gdy wystarczy połączyć dwa ciągi, problem można łatwo rozwiązać, wywołując funkcję strcat(), która dołącza drugi argument na końcu pierwszego argumentu. Podobna funkcja, strncat(), dodaje n znaków z drugiego łańcucha do pierwszego. n jest określone jako trzeci parametr.

A co jeśli sytuacja jest bardziej złożona? Na przykład istnieją dwie niepuste linie i musisz połączyć początek pierwszej i koniec drugiej. Możesz to zrobić za pomocą funkcji strcpy(), jeśli przekazujesz referencje nie do pierwszych znaków napisów:

char s1[ 20 ] = "Piotr Kowalski" , s2 = "Julia Roberts" ; strcpy (s1+ 5 , s2+ 5 ) ; stawia(s1) ;

W ta sprawa Na ekranie pojawi się „Peter Roberts”. Dlaczego to się stało? Do funkcji strcpy() został przekazany wskaźnik do szóstego znaku pierwszego łańcucha. Doprowadziło to do tego, że podczas kopiowania znaki tego ciągu są nadpisywane dopiero od szóstego, ponieważ strcpy() nie „wie” nic o poprzednich znakach. Tylko część ciągu jest również przekazywana jako drugi argument, który jest kopiowany do pierwszego.

Jak wstawić jedną linię w środku drugiej? Możesz rozwiązać ten problem za pomocą trzeciej linii „bufora”, w której możesz najpierw skopiować pierwszą linię, potem drugą, nadpisując koniec pierwszej, a następnie dołączyć koniec pierwszej. Ale możesz też to zrobić:

char s1[ 20 ] = "jeden trzy" , s2[ 20 ] = "dwa" ; strcpy (s2+ 3 , s1+ 3 ) ; strcpy (s1+ 4 , s2) ; stawia(s1) ;

Tutaj najpierw koniec pierwszego jest kopiowany do drugiego wiersza, okazuje się, że „dwa trzy”. Następnie druga linia jest kopiowana do pierwszej linii z pominięciem jej początku.

Opis niektórych funkcji do pracy z ciągami znaków

Ćwiczenia
Poniżej znajdują się opisy niektórych funkcji wykonujących operacje na łańcuchach. Zaprojektuj i napisz małe programy, które ilustrują działanie tych funkcji.

  • char *strchr (const char *, int c) . Zwraca wskaźnik do pierwszego wystąpienia znaku c w łańcuchu. Zwraca NULL, jeśli w łańcuchu nie ma takiego znaku.
  • char *strstr (const char *s2, const char *s1) . Zwraca wskaźnik do pierwszego wystąpienia ciągu s1 w ciągu s2. Jeśli nie ma dopasowań, zwraca NULL.
  • char *strncpy (char *, const char *, size_t n) . Kopiuje n znaków drugiego łańcucha do pierwszego.
  • size_t strspn (const char *, const char *) . Zwraca długość początku pierwszego ciągu zawierającego znaki tworzące drugi ciąg.

Jeśli zauważysz błąd, zaznacz fragment tekstu i naciśnij Ctrl + Enter
UDZIAŁ: