Использование strsep() и его альтернатива

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

int main() {

char *slogan = "together{kaliya} [namak]";
char *slow_gun = strdup(slogan);

char *token = strsep(&slow_gun, "{");

printf ("\n slow_gun: %s\n token: %s\n", slow_gun, token);

return 0;
}

когда я его выполняю:

$ cc -o try try_strsep.c
$ ./try

 slow_gun: kaliya} [namak]
 token: together  

Но когда я меняю char *slogan на:

char *slogan = "kalia} [namak]";

и выполнить ту же программу:

$ vi try_strsep.c 
$ cc -o try try_strsep.c
$ ./try

 slow_gun: (null)
 token: kalia} [namak]

Мой Вопрос таков: когда я использую strsep(), а входная строка не имеет нужного шаблона, возвращаемая функция strsep() неверна. Единственный способ проверить, не удалось ли strsep() найти шаблон, — это проверить if (slow_gun == NUll).

Если у меня есть char *slogan = "together{", то strsep успешно вернет token, но вернет slow_gun пустым (не null)

$ cc -o try try_strsep.c
$ ./try

 slow_gun: 
 token: together

Есть ли способ избежать этой проверки ЕСЛИ и полагаться на функцию, которая вернет мне подстроку, а если ее нет, вернет NULL?


person hari    schedule 28.07.2011    source источник
comment
Вам нужно free строку, возвращенную strdup   -  person Praetorian    schedule 29.07.2011
comment
@Praetorian: Ты довел меня до слез. Я согласен с вами, но поможет ли это мне с моим вопросом?   -  person hari    schedule 29.07.2011
comment
Всегда полезно помочь кому-то избежать утечек памяти :-) Мой ответ ниже должен помочь вам с вашим вопросом.   -  person Praetorian    schedule 29.07.2011
comment
Вы заставили меня задуматься об этом выступлении goo.gl/ks0Oe :)   -  person rahmu    schedule 08.10.2011


Ответы (3)


Нет, нет способа избежать проверки slow_gun == NULL. Вот описание поведения strsep:

char *strsep(char **stringp, const char *delim);

ОПИСАНИЕ
Если *stringp равно NULL, функция strsep() возвращает NULL и больше ничего не делает. В противном случае эта функция находит первую лексему в строке *stringp, где лексемы разделены символами в строке delim. Этот токен завершается путем перезаписи разделителя нулевым байтом ('\0'), а *stringp обновляется, чтобы указывать на токен. Если разделитель не найден, токен принимается за всю строку *stringp, а *stringp заменяется NULL.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
Функция strsep() возвращает указатель на токен, то есть исходное значение *stringp.

Итак, если совпадений не найдено, strsep возвращает указатель на исходную строку и устанавливает вход slow_gun в NULL.

Если разделитель является последним символом в строке, этот символ заменяется на '\0', а slow_gun устанавливается на следующий символ, который оказывается '\0', завершающим исходную строку. Вот почему оператор печати печатает пустую строку.

ПРИМЕЧАНИЕ Вы используете strdup неправильно, вызывающая сторона несет ответственность за вызов free для указателя, возвращаемого этой функцией.

person Praetorian    schedule 28.07.2011

возврат strsep() неверен

Это не правильно. strsep() возвращает первый найденный токен — начало строки по определению является первым токеном. Просто в этом случае не было найдено разделителя, завершающего токен (поэтому оставшаяся часть строки является токеном).

strsep() не предназначен для «поиска шаблона» — он используется для разделения токенов на основе набора разделителей. Если вы хотите найти персонажа, используйте strchr() или strpbrk().

person Michael Burr    schedule 28.07.2011

strsep ведет себя правильно - из справочной страницы:

Функция strsep() находит в строке, на которую ссылается *stringp, первое вхождение любого символа в строке-разделителе (или завершающий символ \0) и заменяет его на \0. Расположение следующего символа после символа-разделителя (или NULL, если был достигнут конец строки) сохраняется в *stringp. Возвращается исходное значение *stringp.

Второй случай правильный — поскольку разделитель не найден, первый параметр устанавливается равным NULL, и возвращается исходная строка. Как вы сказали, вам нужно проверить if (slow_gun == NUll), чтобы обнаружить это.

(кстати, это ужасно запутанный выбор имен переменных).

person John Carter    schedule 28.07.2011