URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 5631
[ Назад ]

Исходное сообщение
"Проблемы с утечкой памяти..."

Отправлено ufobject , 11-Авг-06 15:42 
Народ, я недавно поднимал тему про выделение памяти под строки массива неопределенного размера. Вот ссылочка http://www.opennet.me/openforum/vsluhforumID9/5531.html. Сделал я как мне было сказано, но вот проблемка возникла.. Если я эту функцию только один раз вызову, все будет пучком, но вот если в цикле, тут начинаются проблемы с выделением памятию. Выделять то я ее выделяю calloc'ами, а вот освобождать то некогда! Не могу же я ее вне функции free'й очищать?? Как тут быть?? Можно конечно черти че налепить, изобрести еще пару десятков велосипедов, но хотелось бы оптимального и грамотного решения. У многих ведь наверняка такие проблемы были? HElp!

Содержание

Сообщения в этом обсуждении
"Проблемы с утечкой памяти..."
Отправлено kir , 11-Авг-06 17:53 
а вы правильно опишите проблему
разбирать ваш код это дорого

"Проблемы с утечкой памяти..."
Отправлено ufobject , 11-Авг-06 18:07 
>а вы правильно опишите проблему
>разбирать ваш код это дорого


Эээ. Ну вот, простейший пример..
значит так.

include...

char_array_type foo_funktion (char * string)
{
   tmpstr = strtok (string," ");
   retres[1](char*)=calloc(strlen(tmpstr),sizeof(char*));
   strcpy (retres[1],tmpstr);
   while (tmpstr)
   {
      i++;
      tmpstr = strtok (NULL," ");
      retres[i](char*)=calloc(strlen(tmpstr),sizeof(char*));
      strcpy (retres[i],tmpstr);
   }
   return retres;
}

main.... :)
while (1)
{
  char_array = foo_funktion("PAR1 PAR2 PAR3");
  printf ("%s\n",char_array[1]);
}


Не судите строго, так, от руки накидал чтоб сама фишка была видна. Вот такой код дает постоянное выделение памяти calloc'ом, но читить то мне его негде... Дело в том, что эта функция в дальнейшем будет использоваться еще во многих задачках, и смотреть размер возвращенного массива а потом в цикле делать free -  это не выход.. Как бы избежать утечки?


"Проблемы с утечкой памяти..."
Отправлено phpcoder , 14-Авг-06 09:31 
>   tmpstr = strtok (string," ");

ПРОБЛЕМЫ
       Никогда не используйте эти функции.

>   strcpy (retres[1],tmpstr);

ОШИБКИ РЕАЛИЗАЦИИ
       Если  целевая  строка strcpy недостаточно велика (такое случается, если
       программист идиот/болван и не проверяет размер перед копированием),  то
       может случится ужасное. Переполнение строк фиксированной длины является
       любимым методом крэкеров.

Вообщем, эти функции нерекомендуется использовать.


"Проблемы с утечкой памяти..."
Отправлено ufobject , 14-Авг-06 09:49 
>>   tmpstr = strtok (string," ");
>
>ПРОБЛЕМЫ
>       Никогда не используйте эти функции.
>
>
>>   strcpy (retres[1],tmpstr);
>
>ОШИБКИ РЕАЛИЗАЦИИ
>       Если  целевая  строка
>strcpy недостаточно велика (такое случается, если
>       программист идиот/болван и не проверяет
>размер перед копированием),  то
>       может случится ужасное. Переполнение строк
>фиксированной длины является
>       любимым методом крэкеров.
>
>Вообщем, эти функции нерекомендуется использовать.

1) Немного не понял, strtok нельзя использовать? Почему? В чем опасность? И чем можно заменить?
2) Я почему то расчитываю на то, что переполнения не будет, так как пепед strcpy я выделяю память calloc'ом по размеру tmpstr. Я не вижу тут возможности обмануть выделение памяти для копирования tmpstr. Наверное я не домтаточно знаю про методы?
3) Так как мне все таки организовать функцию, чтоб выделеная память освобождалась (из предыдущего вызова) восвобождалась и организовывался новый массив?


"Проблемы с утечкой памяти..."
Отправлено phpcoder , 14-Авг-06 10:21 
>1) Немного не понял, strtok нельзя использовать? Почему? В чем опасность? И
>чем можно заменить?

Почитайте ман, там абзацем ниже описано почему не рекомендуется и в чем опасность. Чем заменить? Не знаю. Я эту функцию никогда не использовал и кажется плохо себе представляю её назначение. Но может написать её аналог самому и под свои нужны ? или даже просто переделать весь алгоритм -- что знает, может она и не понадобитс вовсе ?

>3) Так как мне все таки организовать функцию, чтоб выделеная память освобождалась
>(из предыдущего вызова) восвобождалась и организовывался новый массив?

Я признаться, не очень понял что вы хотите. Вам должно быть виднее -- действительно ли нужно выделять память? Может лучше не разделять строку, а просто её скопировать с помощью strdup(), а потом пройтись по ней ?


"Проблемы с утечкой памяти..."
Отправлено ufobject , 14-Авг-06 10:48 
>Я признаться, не очень понял что вы хотите. Вам должно быть виднее
>-- действительно ли нужно выделять память? Может лучше не разделять строку,
>а просто её скопировать с помощью strdup(), а потом пройтись по
>ней ?

Не, я думаю это примерно те же яйца только вид с боку Ж)
В общем решил я сделать так: обявить возвращаемый функцией массив как static, а при входе в функцию проверять кол-во элементов в этом массиве и если оно > 0 то обчищаю free'й все элементы... ИМХО, кривоватое решение (static не нравится). Может все такие кто-то более грамотно решал такие задачки?
P.S.

>Я эту функцию никогда не использовал и кажется плохо себе представляю её назначение.

strtoc разбивает строку на подстроки и поочередно возвращает эти самые подстроки, если вдруг интересно. Очень даже полезная функция.

> Почитайте ман, там абзацем ниже описано почему не рекомендуется и в чем опасность.

Посмотрел ман. Может я слишком невнимательный, но никакого предупреждения об опасности использования не нашел... ?


"Проблемы с утечкой памяти..."
Отправлено phpcoder , 14-Авг-06 11:43 
>Посмотрел ман. Может я слишком невнимательный, но никакого предупреждения об опасности использования
>не нашел... ?

Раздел BUGS



"Проблемы с утечкой памяти..."
Отправлено ufobject , 14-Авг-06 12:12 
>>Посмотрел ман. Может я слишком невнимательный, но никакого предупреждения об опасности использования
>>не нашел... ?
>
>Раздел BUGS


Ничего опасного там нет, на мой взгляд. Ну да ладно... Разберусь.
Спасибо за отклик!


"Проблемы с утечкой памяти..."
Отправлено Ganduras , 06-Окт-06 14:36 
>>а вы правильно опишите проблему
>>разбирать ваш код это дорого
>
>
>Эээ. Ну вот, простейший пример..
>значит так.
>
>include...
>


по моему, как раз никакой проблемы.

char **foo(char *s) {
    char **pbuf = NULL;
    char **pp;
    char **end;
    char *p;
    int size = DEFAULT_SIZE;

    if ((pbuf = malloc(sizeof(char *)*size)) == NULL) {
        //printf("FUCK\n");
        return NULL;
    }
    for (p = s, pp = pbuf, end = pbuf + size;;) {
        if (isspace(*p) || *p == '\0') {
endpointer:
            if (pp >= end) {
                 size *= 2;
                 if ((pp = realloc(pbuf, sizeof(*pbuf)*size)) == NULL) {
                      //printf("REALLY FUCK\n");
                      free(pbuf);
                      return NULL;
                 }
                 pbuf = pp;
                 pp = pbuf + size/2;
                 end = pbuf + size;
            }
            *pp++ = s; // или *pp++ = strdup(s);
            if (*p == '\0') {
                if (s == NULL)
                    break;
                s = NULL;
                goto endpointer;
            }
            *p = '\0';
#if 1
            while (isspace(*(s = ++p));
#else
            // если столбец - строго один пробел или \n или \r или еще какой символ, то:
            s = ++p;
#endif
        } else
            ++p;
    }
    return pbuf;
}


Надеюсь понятно что к чему. Ошибки ищи сам :)
Если не используется strdup - то высвободить нужно только один указатель.
Если изменять нельзя строку, например, когда она вкомпилированна в код, или используется в том же виде для обработчиков, то её перед этим надо скопировать (той же strdup).


>Не судите строго, так, от руки накидал чтоб сама фишка была видна.
>Вот такой код дает постоянное выделение памяти calloc'ом, но читить то
>мне его негде... Дело в том, что эта функция в дальнейшем
>будет использоваться еще во многих задачках, и смотреть размер возвращенного массива
>а потом в цикле делать free -  это не выход..
>Как бы избежать утечки?

Есть еще один простой ответ на этот вопрос. Написать функцию для высвыбождения именно этого результата, и пользоваться ей, взамен простого вызова free.


"Проблемы с утечкой памяти..."
Отправлено michelnok , 08-Окт-06 23:11 
>      tmpstr = strtok (NULL," ");
>      retres[i](char*)=calloc(strlen(tmpstr),sizeof(char*));

Кстати, а зачем выделять в sizeof(char*) раз больше памяти чем надо?
Когда исправите на sizeof(char), то не забудте прибавить 1 для завершающего нуля.

Насчет вопроса как такового. Что мешает вызвать free в цикле для всех элементов retres (кроме нулевого, вы почему-то его не трогаете)?

Ну и непонятно почему retres глобальный и кто вам сказал что в string окажется меньше токенов чем его длина-1?

Насчет потенциальных проблем, указанных phpcoder'ом, то в данном конкретном случае они некритичны.


"Проблемы с утечкой памяти..."
Отправлено vvvua , 01-Сен-06 03:36 
Обрати внимание на сборщик мусора gd.
libgd поможет, думаю.