Функции за обработка на низове. Man strtok_r(3): извлича елементи (токени) от низ Strtok s c описание

4 отговора

Две неща, които трябва да знаете за strtok. Както споменахме, той „поддържа вътрешно състояние“. Освен това той обърка линията, която го захранваш. По същество ще напише "\0", където ще намери токена, който сте предоставили, и ще върне указател към началото на реда. Вътрешно той поддържа местоположението на последния токен; и следващия път, когато го извикате, ще започне от там.

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

„Хубавото“ на strtok е, че всъщност не копира низове, така че не е нужно да управлявате допълнително разпределение на паметта и т.н. Но ако не разбирате горното, ще имате проблеми с използването му.

Пример. Ако имате "this, is, a string", последователните извиквания на strtok ще генерират указатели като този (стойността на ^ е върнатата стойност). Обърнете внимание, че "\0" се добавя там, където са намерени жетони; това означава, че оригиналният ред е променен:

T h i , i s , a , s t r i n g \0 this,is,a,string t h i s \0 is , 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 ^ това е \0 is \0 a \0 s t r i n g \0 низ ^

Дано това има смисъл.

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

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

strtok поддържа вътрешно състояние. Когато го извикате с не-NULL, той се инициализира повторно, за да използва низа, който предоставяте. Когато го извикате с NULL, той използва този низ и всяко друго състояние, което има в момента, за да върне следващия токен.

Поради начина, по който работи strtok, трябва да се уверите, че свързвате към многонишковата версия на C runtime, ако пишете многонишково приложение. Това гарантира, че всяка нишка получава собствено вътрешно състояние за strtok.

Функцията strtok съхранява данни във вътрешна статична променлива, която се споделя между всички нишки.

За безопасност на нишката трябва да използвате strtok_r

Разгледайте static char *last;

Char * strtok(s, delim) регистър char *s; регистър const char *delim; ( register char *spanp; register int c, sc; char *tok; static char *last; if (s == NULL && (s = last) == NULL) return (NULL); /* * Пропускане (span) водещ разделители (s += strspn(s, разделяне), вид). */ продълж.: c = *s++; for (spanp = (char *)delim; (sc = *spanp++) != 0;) ( if (c == sc) goto cont; ) if (c == 0) ( /* няма знаци без разделител */ last = NULL; return (NULL); ) tok = s - 1; /* * Сканиране на токен (сканиране за разделители : s += strcspn(s, delim), нещо като). * Имайте предвид, че delim трябва да има един NUL; спираме, ако видим и това. */ за (;;) ( c = *s++; spanp = (char *)delim; do ( if ((sc = *spanp++) == c) ( if (c == 0) s = NULL; else s[-1] = 0; last = s; return (tok); ) ) докато (sc != 0); ) /* НЕДОСТИГНАТО */ )

дял

Описание

Функцията strtok търси токени в низа низ. Поредица от извиквания на тази функция разделя низа на токени, които са поредици от символи, разделени от символи за разделяне.

При първото извикване функцията приема низ като аргумент, чийто първи знак се използва като начална точка за търсене на токени. При следващи извиквания функцията изчаква нулев указател и използва позицията непосредствено след края на последния токен като ново местоположение за сканиране.

За да определи началото на токен, функцията първо определя знаците, които не се съдържат в низа delim, тоест те са разделителни знаци. И след това проверява останалата част от низа символ по знак до първия знак за разделител, който сигнализира края на токена.

Този завършващ токен автоматично се заменя с нулев знак и токенът се връща от функцията. След това следващите извиквания на функцията strtok започват с този нулев знак.

Настроики:

  • низ
    Низ за търсене на лексеми. Съдържанието на този низ ще бъде променено, ще бъде разделено на по-малки низове (токени). Този параметър може да съдържанулев указател, в който случай функцията продължава да сканира от мястото, където е спряло предишното успешно извикване на функция.
  • делим
    Низ, съдържащ разделители. Те могат да варират от едно извикване на функция до извикване на друга функция.

Върната стойност

Указател към последния намерен маркер в низа.
Връща се нулев указател, ако не бъдат намерени токени.

Пример: изходен код на програма

//пример за използване на функцията strtok #include #включи int main () ( char str = "Характеристики на националния риболов - игрален, комедиен филм."; std::cout<< "Разделение строки "" << str << "" на лексемы:n"; char * pch = strtok (str," ,.-"); // во втором параметре указаны разделитель (пробел, запятая, точка, тире) while (pch != NULL) // пока есть лексемы { std::cout << pch << "n"; pch = strtok (NULL, " ,.-"); } return 0; }

Езиците за програмиране могат да включват специални функции за манипулиране на низове, като по този начин елиминират необходимостта програмистът да пише свои собствени функции за обработка на низове. Например, често трябва да определите дължината на низ и следователно езиците предоставят функция, която измерва дължината му.

В езика за програмиране C функциите за работа с низове се декларират в заглавния файл string.h, който трябва да запомните да включите във вашия изходен код. Има около двадесет функции за работа с низове. Сред тях има такива, които търсят знаци в низ, функции за сравнение, копиране на низове, както и по-специфични. Списък и описание на повечето функции, съществуващи в момента в езика C, могат да бъдат намерени в приложението към книгата "Езикът за програмиране C. Второ издание" от B. Kernighan и D. Ritchie.

Всички функции, декларирани в string.h, по време на тяхната работа могат да променят или да не променят един от низовете, предадени от указателя. Зависи от целта на функцията. Повечето от тях обаче връщат нещо: или указател към знак, или цяло число. Освен това, ако дадена функция промени един от своите параметри и е била извикана за тази цел, тогава това, което връща, може да бъде игнорирано (т.е. да не бъде присвоено на нищо в извикващата функция).

Например функцията strcpy() има следната декларация: char *strcpy (char *, const char*) . Той копира низа, към който сочи вторият параметър, в низа, към който сочи първият параметър. Така се променя първият параметър. Освен това функцията връща указател към първия символ на низа:

char s1[10], s2[10]; char * s3; s3 = s2; получава (s1); s3 = strcpy(s2, s1); поставя (s2); поставя (s3); printf("%p, %p \н", s2, s3) ;

Тук s2 и s3 сочат към един и същ символ (printf() извежда едни и същи адреси). Въпреки това, това, което strcpy() връща, не може да бъде присвоено на масив. Резултатът от тази функция обикновено не се присвоява на нищо; Понякога е достатъчно просто да промени един от низовете, предадени от показалеца.

Друго нещо са функции като strlen() или strcmp(), които не променят параметрите, но се извикват в името на резултата. Функцията strcmp() сравнява два аргументни низа буква по буква (лексикографски) и връща 0, -1 или 1. Например извикването на strcmp("boy", "body") ще върне 1, защото Кодът на буквата "y" е по-голям от буквата "d". Извикването на strcmp("body", "boy") ще върне -1, защото първият аргумент е лексикографски по-малък от втория.

функция strtok()

С помощта на функцията strtok() можете да разделите низ на отделни части (токени). Декларацията на тази функция изглежда така: char *strtok (char *, const char *) . Когато функцията се извиква за първи път, първият параметър е низът, който трябва да бъде разделен. Вторият параметър указва разделителния низ. При следващи извиквания на функцията за същия низ, първият параметър трябва да бъде NULL, т.к функцията вече си е "запомнила" с какво работи. Да разгледаме един пример:

char str = "едно, две, три, четири, пет"; char * sp; sp = strtok (str, "," ); докато (sp) ( поставя (sp); sp = strtok (NULL, ", ") ; )

В резултат на изпълнението на този код на екрана в колона се показват следните думи:

Едно две три четири пет

При първото извикване на strtok() към функцията се предават указател към първия знак от масива и разделителен низ. След това извикване масивът str се променя, в него остава само думата "one", като функцията връща и указател към тази дума, който е присвоен на sp.

Въпреки че загубихме останалата част от масива в извикващата функция, указател към останалата част от масива се съхранява в strtok(). Когато се подаде NULL, функцията "знае" да работи с тази "опашка".

Копиране на части от низове

Когато просто трябва да свържете два низа, проблемът се решава лесно чрез извикване на функцията strcat(), която добавя втория към края на първия аргумент. Подобна функция, strncat(), добавя n знака от втория низ към първия. n е посочен като трети параметър.

Ами ако ситуацията е по-сложна? Например, има два непразни реда и трябва да свържете началото на първия и края на втория. Това може да стане с помощта на функцията strcpy(), ако подадете препратки не към първите знаци на редовете:

char s1[ 20 ] = "Питър Смит", s2 = "Джулия Робъртс"; strcpy (s1+ 5, s2+ 5); поставя (s1);

В този случай на екрана ще се покаже "Питър Робъртс". защо стана така Указател към шестия знак на първия ред беше предаден на функцията strcpy(). Това доведе до факта, че при копиране знаците на този ред се презаписват едва от 6-ти, т.к. strcpy() не "знае" нищо за предишните знаци. Само част от низа също се предава като втори аргумент, който се копира в първия.

Как да вмъкна един ред в средата на друг? Можете да разрешите този проблем, като използвате трети „буферен“ ред, където можете първо да копирате първия ред, след това втория, като изтриете края на първия и след това добавите края на първия. Но можете да направите и това:

char s1[ 20 ] = "едно три" , s2 [ 20 ] = "две" ; strcpy (s2+ 3, s1+ 3) ; strcpy (s1+ 4, s2); поставя (s1);

Тук първо краят на първия се копира във втория ред, което води до „две три“. След това вторият ред се копира в първия ред, заобикаляйки началото му.

Описание на някои функции за работа с низове

Упражнение
По-долу са описани някои функции, които извършват операции върху низове. Проектирайте и напишете малки програми, за да илюстрирате как работят тези функции.

  • char *strchr (const char *, int c) . Връща указател към първото срещане на знака c в низа. Връща NULL, ако в низа няма такъв знак.
  • char *strstr (const char *s2, const char *s1) . Връща указател към първото срещане на низ s1 в низ s2. Ако няма съвпадения, връща NULL.
  • char *strncpy (char *, const char *, size_t n) . Копира n знака от втория ред в първия.
  • size_t strspn (const char *, const char *) . Връща дължината на началото на първия низ, който включва знаците, съставляващи втория низ.

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

Описание:

Функцията strtok() връща указател към следващия токен в низа, към който сочи str1. Знаците от низа, към който сочи str2, се използват като разделители, които дефинират токена. Ако токенът не бъде намерен, се връща NULL.

Първото извикване на strtok() всъщност използва str1 като указател. Следващите извиквания използват NULL като първи аргумент. По този начин целият низ може да бъде разбит на токени.

Важно е да се разбере, че функцията strtok() променя низа, към който сочи str1. Всеки път, когато се намери токен, нулев знак се поставя на мястото, където е намерен разделителят. Така strtok() напредва по линията.

Всяко извикване на strtok() ви позволява да променяте набора от разделители.

Функцията _fstrtok() е FAR версията на въпросната функция.

Следващата програма токенизира низа „Летният войник, слънчевият патриот“, използвайки интервали и запетаи като разделители. В резултат на работата на програмата ще се генерира следният ред: „The | лято | войник | | слънце | патриот."
#включи
#включи
int main(void)
{
char * p;
p = strtok ( "Летният войник, слънчевият патриот", " " ) ;
printf(p);
направи (
p= strtok(" \0 " , ", " ) ;
if (p) printf ("|% s", p) ;
) докато (p) ;
връщане 0;
}



Свързани публикации