Народ, я недавно поднимал тему про выделение памяти под строки массива неопределенного размера. Вот ссылочка http://www.opennet.me/openforum/vsluhforumID9/5531.html. Сделал я как мне было сказано, но вот проблемка возникла.. Если я эту функцию только один раз вызову, все будет пучком, но вот если в цикле, тут начинаются проблемы с выделением памятию. Выделять то я ее выделяю calloc'ами, а вот освобождать то некогда! Не могу же я ее вне функции free'й очищать?? Как тут быть?? Можно конечно черти че налепить, изобрести еще пару десятков велосипедов, но хотелось бы оптимального и грамотного решения. У многих ведь наверняка такие проблемы были? HElp!
а вы правильно опишите проблему
разбирать ваш код это дорого
>а вы правильно опишите проблему
>разбирать ваш код это дорого
Эээ. Ну вот, простейший пример..
значит так.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 - это не выход.. Как бы избежать утечки?
> tmpstr = strtok (string," ");ПРОБЛЕМЫ
Никогда не используйте эти функции.> strcpy (retres[1],tmpstr);
ОШИБКИ РЕАЛИЗАЦИИ
Если целевая строка strcpy недостаточно велика (такое случается, если
программист идиот/болван и не проверяет размер перед копированием), то
может случится ужасное. Переполнение строк фиксированной длины является
любимым методом крэкеров.Вообщем, эти функции нерекомендуется использовать.
>> tmpstr = strtok (string," ");
>
>ПРОБЛЕМЫ
> Никогда не используйте эти функции.
>
>
>> strcpy (retres[1],tmpstr);
>
>ОШИБКИ РЕАЛИЗАЦИИ
> Если целевая строка
>strcpy недостаточно велика (такое случается, если
> программист идиот/болван и не проверяет
>размер перед копированием), то
> может случится ужасное. Переполнение строк
>фиксированной длины является
> любимым методом крэкеров.
>
>Вообщем, эти функции нерекомендуется использовать.1) Немного не понял, strtok нельзя использовать? Почему? В чем опасность? И чем можно заменить?
2) Я почему то расчитываю на то, что переполнения не будет, так как пепед strcpy я выделяю память calloc'ом по размеру tmpstr. Я не вижу тут возможности обмануть выделение памяти для копирования tmpstr. Наверное я не домтаточно знаю про методы?
3) Так как мне все таки организовать функцию, чтоб выделеная память освобождалась (из предыдущего вызова) восвобождалась и организовывался новый массив?
>1) Немного не понял, strtok нельзя использовать? Почему? В чем опасность? И
>чем можно заменить?Почитайте ман, там абзацем ниже описано почему не рекомендуется и в чем опасность. Чем заменить? Не знаю. Я эту функцию никогда не использовал и кажется плохо себе представляю её назначение. Но может написать её аналог самому и под свои нужны ? или даже просто переделать весь алгоритм -- что знает, может она и не понадобитс вовсе ?
>3) Так как мне все таки организовать функцию, чтоб выделеная память освобождалась
>(из предыдущего вызова) восвобождалась и организовывался новый массив?Я признаться, не очень понял что вы хотите. Вам должно быть виднее -- действительно ли нужно выделять память? Может лучше не разделять строку, а просто её скопировать с помощью strdup(), а потом пройтись по ней ?
>Я признаться, не очень понял что вы хотите. Вам должно быть виднее
>-- действительно ли нужно выделять память? Может лучше не разделять строку,
>а просто её скопировать с помощью strdup(), а потом пройтись по
>ней ?Не, я думаю это примерно те же яйца только вид с боку Ж)
В общем решил я сделать так: обявить возвращаемый функцией массив как static, а при входе в функцию проверять кол-во элементов в этом массиве и если оно > 0 то обчищаю free'й все элементы... ИМХО, кривоватое решение (static не нравится). Может все такие кто-то более грамотно решал такие задачки?
P.S.>Я эту функцию никогда не использовал и кажется плохо себе представляю её назначение.
strtoc разбивает строку на подстроки и поочередно возвращает эти самые подстроки, если вдруг интересно. Очень даже полезная функция.
> Почитайте ман, там абзацем ниже описано почему не рекомендуется и в чем опасность.
Посмотрел ман. Может я слишком невнимательный, но никакого предупреждения об опасности использования не нашел... ?
>Посмотрел ман. Может я слишком невнимательный, но никакого предупреждения об опасности использования
>не нашел... ?Раздел BUGS
>>Посмотрел ман. Может я слишком невнимательный, но никакого предупреждения об опасности использования
>>не нашел... ?
>
>Раздел BUGS
Ничего опасного там нет, на мой взгляд. Ну да ладно... Разберусь.
Спасибо за отклик!
>>а вы правильно опишите проблему
>>разбирать ваш код это дорого
>
>
>Эээ. Ну вот, простейший пример..
>значит так.
>
>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.
> tmpstr = strtok (NULL," ");
> retres[i](char*)=calloc(strlen(tmpstr),sizeof(char*));Кстати, а зачем выделять в sizeof(char*) раз больше памяти чем надо?
Когда исправите на sizeof(char), то не забудте прибавить 1 для завершающего нуля.Насчет вопроса как такового. Что мешает вызвать free в цикле для всех элементов retres (кроме нулевого, вы почему-то его не трогаете)?
Ну и непонятно почему retres глобальный и кто вам сказал что в string окажется меньше токенов чем его длина-1?
Насчет потенциальных проблем, указанных phpcoder'ом, то в данном конкретном случае они некритичны.
Обрати внимание на сборщик мусора gd.
libgd поможет, думаю.