LINUX.ORG.RU

Вдруг начал падать trim

 


0

1

Работал, что-то поменялось и вдруг перестало. Парадает на //1, если есть пробелы в конце, падает на //2 если в начале. Предпосылок падению не вижу, что не так?

char * trim(char * line)
{
    size_t    len = 0;
    char * frontp = line - 1;
    char * endp   = NULL;

    if (!(line))
        return NULL;

    if (line[0] == '\0')
        return line;

    len  = strlen(line);
    endp = line + len;

    while (isspace(*(++frontp)));
    while (isspace(*(--endp)) && endp != frontp);

    if (line + len - 1 != endp)
    {
        *(endp + 1) = '\0'; //1
    }
    else
    {
        if (frontp != line && endp == frontp)
            *line = '\0';
    }

    endp = line;
    if (frontp != line)
    {
        while (*frontp)
            *endp++ = *frontp++; //2
        *endp = '\0';
    }

    return line;
}

★★

Последнее исправление: cetjs2 (всего исправлений: 1)

while (isspace(*(--endp)) && endp != frontp);
if (line + len - 1 != endp)

т.е. ты сначала используешь переменную в цикле, а потом ещё и в условии? Очевидно, что этот фрагмент нужно оптимизировать. А если ты не понимаешь, о чём речь - вставь ещё проверку.

ziemin ★★
()
Ответ на: комментарий от ziemin

Здесь так и должно быть.

Код вообще со stackoverflow, причем на тех тестовых значениях, что там выложил автор оно работает. А на таком коде падает:

    char * br = " (34,  21)  , (22, 34), (0xFF00FF, 0xFF00FF), (9, 21)  ";

    br = trim(br);

sambist ★★
() автор топика
Ответ на: комментарий от wakuwaku

Хорошо, предположим, что он имел его в виду.

сравнение с '0' - плохой тон

Что он курил? Пусть покажет, например, в K&R этот пункт.

Что по-твоему происходит?

if (line[0] == '\0')
        return line;

Разъясняю:
Если первый символ в строке - нуль-терминатор, то дальнейшие действия бессмысленны и мы возвращаем эту пустую строку обратно.

sambist ★★
() автор топика
Ответ на: комментарий от sambist
if (!(line))
    return NULL;
if (line[0] == '\0')
    return line;

wut

мой trim выглядит примерно так

static char *trim(char *s)
{
	if (!s) return "";
	char *h, *t;
	for (h=s;isspace(*h);h++);
	for (t=s+strlen(s)-1;isspace(*t);t--)
	*(t+1) = '\0';
	return h;
}

wakuwaku ★★★★
()
Ответ на: комментарий от wakuwaku

wut

Что? Первое - проверка на NULL, второе - на "".

мой trim выглядит примерно так

У вас там есть проблема. Придется хранить исходную строку где-то, потом делать ей free и ни в коем случае не делать free тому, что вернулось из вашего trim'а.

sambist ★★
() автор топика

Фейспалмов тред.

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

char *
trim(char *s)
{
    char *f = NULL, *e = s;

    if (s) {
        for (char *t = s; *t; t++)
            if (!isspace(*t)) {
                if (!f) f = t;
                e = t+1;
            }
        *e = 0;
    }
    return f ? f : s;
}

int
main(int argc, char *argv[])
{
    const char *ss[] = {
        "qwe asd",
        " qwe asd",
        "qwe asd ",
        " qwe asd ",
        "   ",
        "",
        NULL,
    };

    for (size_t i = 0; i < sizeof(ss) / sizeof(*ss); i++) {
        char *s = ss[i] ? strdup(ss[i]) : NULL;
        printf("'%s'\n", trim(s));
        free(s);
    }
    return 0;
}
'qwe asd'
'qwe asd'
'qwe asd'
'qwe asd'
''
''
'(null)'
arturpub ★★
()
Ответ на: комментарий от sambist

У вас там есть проблема. Придется хранить исходную строку где-то, потом делать ей free и ни в коем случае не делать free тому, что вернулось из вашего trim'а.

char *
trim(char *s)
{
    if (s) {
        char *t, *f = NULL, *e = s;
        for (t = s; *t; t++) {
            if (!isspace(*t)) {
                if (!f) f = t;
                e = t-(f-s)+1;
            }
            if (f) s[t-f] = *t;
        }
        *e = 0;
    }
    return s;
}
arturpub ★★
()
Ответ на: комментарий от arturpub
char *
trim(char *s)
{
    char *t, *f = NULL, *e = s;
    for (t = s; s && *t; t++) {
        if (!isspace(*t)) e = t-((f?f:(f=t))-s)+1;
        if (f) s[t-f] = *t;
    }
    return s && (*e = 0), s;
}

Короче не получается, извиняйте.

arturpub ★★
()

Ну внесите уже царя!

buddhist ★★★★★
()
Ответ на: комментарий от Gvidon

Это сишка, лалки. Если включить мозг, то суть происходящего тривиальна. Конкурс обфускации устроили в оп, где функция в шесть раз длинее в три прохода делает не то, и никто из вас не может сказать почему ;)

arturpub ★★
()
    if (!(line))
        return NULL;

    if (line[0] == '\0')
        return line;

Я никогда не понимал такого зоопарка в стилях. Почему не писать однообразно: либо

    if (line == NULL)
        return NULL;

    if (line[0] == '\0')
        return line;
либо
    if (!line)
        return NULL;

    if (!line[0])
        return line;

А в данном случае вообще надо

    if (line == NULL || line[0] == '\0')
        return line;

akk ★★★★★
()
char * frontp = line - 1;

    if (!(line))
        return NULL;

То есть сначала мы используем переменную, а потом проверяем, а можно ли это делать. Прелестно. Откуда код? Со стековерфлоу, говоришь?

akk ★★★★★
()
Последнее исправление: akk (всего исправлений: 1)

Действительно фейспалмов тред

char * trim(char * line)
{
    if (!line) return NULL;

    char * front = line;
    while (*front && isspace(*front)) ++front;

    char * end = front;
    char * x = end;
    while (*x) if (!isspace(*x++)) end = x;

    *end = 0;
    memmove(line, front, end - front + 1);
    return line;
}
anonymous
()
Ответ на: комментарий от arturpub

и правда. я не помню зачем там мне могло понадобиться t+1 там, вероятно образовалось в процессе переписывания и упрощения. этот код я использую для личных нужд уже много лет на регулярной основе (в бинарном виде) и впервые столкнулся с данной проблемой. похоже, слишком хорошие входные данные попадались. // посмотрел, ошибка там будет от «item1, item2 , item3», у меня никогда не возникает желания отделять запятые пробелом.

wakuwaku ★★★★
()
Последнее исправление: wakuwaku (всего исправлений: 2)
Ответ на: комментарий от Gvidon

Читаемый вариант чуть выше свернутого. В общем-то читаемость для таких случаев это миф, т.к. размазня на несколько страниц не улучшает качества кода, хотя бы из-за количества строк и известного правила, которого хватило, чтобы тс запутался. Таких алгоритмов мало, но их часто вызывают, поэтому стоит озаботиться. К нему всегда пишется небольшое описание, после чего он парсится интуитивно (его сложнее писать, чем читать, хотя тут можно было попробовать пожертвовать парой строк и назвать все так, чтобы нубопитонисту было иногда очевидно без комментов, но граничка берет свое). Конкретно здесь находится первый непробел, после этого символы начинают незаметно переезжать в начало строки, а последний найденный непробел+1 заменяется нулем, все за один проход, без паразитных strlen и memmove. Плюс граничные условия в виде нулл или нет букв. Этих проверок и арифметики переноса можно было бы избежать, тогда читаемость была бы выше, но тс-а принципиально не устраивает идиоматическое f = trim(s, &e), так что они присутствуют.

arturpub ★★
()
Ответ на: комментарий от arturpub

Смотри код анонимуса чуть выше, коротко и просто.

Gvidon ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.