И это у вас работает? Какой компилятор, если не секрет?
-----
main()
{
static char *str = "Hello";
puts("Run test");
puts(strip_spaces(str));
return 0;
}
----
> Как и следовало ожидать с указателями народ работать не умеет.
Ну вы то умеете. Вон даже и psz приписываете.
А со static ни кто не обещал, что будет работать. К тому же функция реализован из тех же принципов что и станадртная strcat, так что притензии по параметрам к Кернигану на пару с Риччи. Ну а то что мой вариант куда проще чем пионерские поделки я думаю, ты по своей не далекости, не заметил.
PS psz я пишу для себя, а не для кого-то.
PPS Таких притензий, как длинный и не оптимальный код я так понимаю нет. Так что жду слов "Спасибо"...
Какой побочный эффект? Модификация строки? Ты man strcat набирал или нет? Ты где-нибудь видел слово static в объявлении параметра функции? Может ты того... Почитаешь что-нибудь скажем того же Кернигана, прежде чем тут говорить?
> Проверял на примере от 2003-06-16 23:11:56.137365 - получил segfault, как и следовало ожидать
Ты язык С знаешь? Мне кажется что нет. Опять таки сделай man strcat прежед чем говорить.
> Так и случай такой.
Тут случай такой, что ни какая state-machine не нужна. Просто нужно видеть решение задачи.
PS Ты автор какой реализации? Первой или второй? А то у меня ко второй реализации очень большие претензии.
Мда... В общем до тебя так и не дошло. Подсказываю: прочитай книжку на тему char *blah = "blah-blah" и char blah[] = "blah-blah"
Как тебе ещё объяснить твою глупость я не знаю.
PS Чтоб не было вопросов: код проверялся на
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/specs
gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)
> Какой побочный эффект? Модификация строки? Ты man strcat набирал или нет?
Ну так. Давно известно, что strcat - проблемная функция.
> Ты где-нибудь видел слово static в объявлении параметра функции?
Это вы к чему? Поясните пожалуйста.
> Может ты того... Почитаешь что-нибудь скажем того же Кернигана, прежде чем тут говорить?
Читал.
> Ты язык С знаешь? Мне кажется что нет. Опять таки сделай man strcat прежед чем говорить.
Что вы постоянно киваете на strcat? Плохая это функция. Хорошая выглядела бы так: int str_cat(const char *part1, const char *part2, char *dst, int size);
> Тут случай такой, что ни какая state-machine не нужна. Просто нужно видеть решение задачи.
Тут я с вами и не особо спорил. Но какие у вас возражения? Пример дюже простой?
> PS Ты автор какой реализации? Первой или второй? А то у меня ко второй реализации очень большие претензии.
Второй. Но у меня к ней у самого остались претензии - входные условия неправильно проверяет (не хотел исправлять - раз уж тут спор развязался). Очень интересно услышать ваши претензии.
У strcat всего одна проблема - не проверяет длину строки куда копировать, а в остальном проблем нет. Не зря была придумана strncat. Но моя функция такой проблемы не имеет по очевидным причинам.
>> Ты где-нибудь видел слово static в объявлении параметра функции?
> Это вы к чему? Поясните пожалуйста.
Имелось ввиду const (а не статик), если бы было написано strip_spaces( const char *pszStr ) То юзер видел бы, что строку модифицировать не будут, а раз const нет, то будут. У тебя с этим проблемы?
> Что вы постоянно киваете на strcat? Плохая это функция
Хорошая функция, делает ровно то что заказывали - соединяет две строки и без кучи лишних параметров и очень удобно пользоватся: strcat( strcat( str ), str2 )
> Второй. Но у меня к ней у самого остались претензии - входные условия неправильно проверяет (не хотел исправлять - раз уж тут спор развязался). Очень интересно услышать ваши претензии
Всегда пожалуйста:
1) size должен быть не int, а size_t
2) Может проще было всю эту конструкцию через for сделать, хоть смотрелась бы более проще.
> Это до вас не дошло. Различие я прекрасно знаю. Но пример есть? Компилится? Сегфаултится?
Какой сегфолтится char *? Так ему Керниган завещал сегфолтится. А вот char [] прекрасно работает.
> Да уж как-нибудь постарайтесь, автор безопасной функции, к которой нужно прилагать инструкцию по использованию.
Функция безопасна, потому как её прототип является наглядной документацией.
Я другой ананимус.
Мне лично понравился код со состоянием (только я бы его переделал бы по своему), но испльзовал бы, как Ogr, одну строковую переменную.
примерно так (не тестировал):
char *strip_spaces(char *src)
{
int in_space = 0;
char *dst=src;
cahr *ret=src;
/*
* try this,
* to prevent memory leaks
* you should get free the result string
* if you dont need it anymore
* sorry for english, I hate translit :-)
*/
char *trim(char *str)
{
char *buf, *p;
if (!str)
return NULL;
if (!(buf = (char *) calloc(strlen(str) + 1, 1)))
exit(1);
p = buf;
while (*str) {
*p++ = *str++;
if (*(p - 1) == ' ')
while (*str == ' ')
str++;
}
buf = (char *) realloc(buf, strlen(buf) + 1);
return buf;
}
agat
2anonymous (*) (2003-06-17 09:02:23.438704):
> В варианте Ogr, мне не понравилось смесь обращения к содержимому указателей и индексов.
Я же говорю, не умеет народ с указателями работать. Вот их и пугает указатели с индексами... Ну напиши так: if( *(pszCur+1) != ' ' || *pszCur != ' ' ) для компилятора абсолютно ни какой разницы.
2anonymous (*) (2003-06-17 10:32:05.41423):
> я так и не понял char* raz = "blah"; char dva[] = "blah"; и шо? где разница?
int main( void )
{
char str1[] = "This is a first string";
char *str2 = "This is a second string";
puts( "Start test:" );
puts( strip_spaces(str1) );
puts( strip_spaces(str2) );
return 0;
}
Запусти это на линуксе, используя мою функцию, и прочуствуй разницу. Может К&R прочитаешь за одно.
если я не ошибаюсь, то
str[]="типа моя строчка";
означает, что память - таки выделена и эту строку можно
менять, работая указателем.*(str+1) = 'р';
*str="типа ещё моя строчка"; При попытке изменить
выдаст Segmentation Fault. Вот так.
Разница между char * и char [] в том, что char *str = "str" указывает на статическую область памяти и соответсвенно изменение в этой области может привести к coredump, в то время как char str[] = "str" выделяет память под объект в области данных (в данном случае стека) и дает возможность менять содержимое строки.
>> В варианте Ogr, мне не понравилось смесь обращения к содержимому указателей и индексов.
>Я же говорю, не умеет народ с указателями работать. Вот их и пугает указатели с индексами... Ну напиши так: if( *(pszCur+1) != ' ' || *pszCur != ' ' ) для компилятора абсолютно ни какой разницы.
Ну, дык, и написал бы так, а то отговорки начались. Если * - то указатель, если [] - то индекс.
И зачем, каждую позицию, ты проверяешь дважды на равенство с пробелом? С первого раза не понимаешь? :)
> *pszStr = *pszCur; // скопировать \0
И нулевой символ можно порсто присвоить, зачем его доставать из памяти.
Если серьёзно, это я так прикапываюсь. Но обвинять народ, что не умеет работать с указателями, не надо.
Тут что, устроили конкурс "тысяча и один способ убрать повторяющиеся пробелы" :-) ?
Тогда и я свой вариант подкину:
char* remove_double_spaces(char *str)
{
char *src = str, *dst = str;
while(*src){/*Перебираем строку*/
if (*src==' '){
while (*(++src)==' ');/*Если пробел, значит не '\0'*/
*(dst++) = src[-1];/*Копируем последний (или единственный) пробел*/
}
else
*(dst++) = *(src++);
}
*dst = '\0'; //*src;
return str;
}
Вариант Ogr всем хорош, есть только одна непонятка, именно, зачем нужна проверка аргумента на 0.
Поясняю. У функции есть как минимум 4 способа налететь на segfault и иже с ним:
1. Аргумент равен 0
2. Аргумент указывает на read-only memory (обсуждалось)
3. Аргумент указывает вообще черт знает куда
4. Аргумент указывает в хорошее место, но лежит там не строка (так что цикл завершится не по условию, а опять-таки аварийно).
Зачем из четырех равноправных ошибок проверять одну?
проблема в том что если в какой то момент времени pszCurr(или как
его там) указывает на последний байт байт на границе, то есть картинка
выглядит так:
min -----> max /* куда растет паметь */
---read-write-memory---+---out-of-bound-memory---
... |3|7|
-----------------------+-------------------------
^
|
pszCurr
то есть значение *pszCurr равно pszCurr[0] равно 7 - цикл продолжается,
но в момент доступа к pszCurr[1] будет обращение к левой памяти
которая не в поле зрения процесса то есть возникнет ошибка.
Да кстати, чтоб программа была совсем правильная выражение: pszCur[0] != ' ' должно быть записано как !isspace( pszCur[0] ), в таком случае программа правильно будет работать даже в многоязычной среде. Хотя для char * это смысла мало имеет, а вот для wchar_t * очень даже...
> Хорошая функция, делает ровно то что заказывали - соединяет две строки и без кучи лишних параметров и очень удобно пользоватся: strcat( strcat( str ), str2 )
Вы бы привели типичный кусок кода, использующего strcat. Сам вызов прост, но требует нехилой обвязки. _Один_ лишний параметр - небольшая цена за удобство.
> size должен быть не int, а size_t
Личное дело каждого. Если я изменю имя size на count, вы разрешите переменной быть типа int? (Ну не нравится мне unsigned - с нулем очень неудобно сравнивать).
> Может проще было всю эту конструкцию через for сделать, хоть смотрелась бы более проще.
А что там выносить наверх, кроме src++? А проще/непроще - главное точнее выражает идею.
to anonymous (*) (2003-06-20 02:32:57.180729):
> С вызовами strlen, calloc и realloc? Не смешите.
char *trim(char *str)
{
char *buf, *p;
if (!str)
return NULL;
buf = str;
p = buf;
while (*str) {
*p++ = *str++;
if (*(p - 1) == ' ')
while (*str == ' ')
str++;
}
*p = '\0';
return buf;
}
конечно можно и так, но тогда будет проблема
с char* / char[]. Ну а realloc в принципе тоже не так уж
глупо - если функция вызывается редко и str имеет большое
кол-во пробелов. Не нравится - закомментируй.