LINUX.ORG.RU

Пиатницо, return statement


0

1

Привет.
1.

int funcA()
{
   if () return 2;
   if () return 1;
   // do some more
   return 0;
}

2.

int funcA()
{
   error = 0;
   do {
      if () {
         error = 2;
         break;
      }
      if () {
         error = 1;
         break;
      }
      // do some more
   }
   while(0);
   return error;
}

3.

int funcA()
{
   if () goto ERROR;
   if () goto ERROR;
   // do some more
ERROR:
   return 0;
}

Ваш вариант и аргументы? ) Дискасс! =)

★★★★★

Ответ на: комментарий от ilammy

Но это проблемы Сишечки, потому что там явный memory-management.

Ерунда. Это проблемы кривого проектирования не читавших SICP персонажей. Я привёл примеры как можно легко и получая более читаемый код обойтись без goto. Особенно если нормально раскидать всё по функциям, а не лепить по принципу один файл - одна функция. В особенно критичных местах правда goto может давать прирост произодительности, иногда это действительно важно.

(Спорный.) Для выхода из глубоко вложенных циклов

Всё правильно, спорный. Здесь goto только приведёт к бажности и запутанности. Это я и имел в виду, когда говорил про прогу на фортране.

auto12884839
()
Ответ на: комментарий от beastie

Всех с детства учили бояться барабашек, серенького волчка и goto.

Deleted
()
Ответ на: комментарий от auto12884839

игнорирование утверждений по причине несовременной терминологии.

когда goto использовать не так уж и вредно

у ТС не произвольное goto ( c великим goto в середину незапущенной(из точки goto) процедуры (что вообще нетривиальная семантика в части как устанавливать аргументы при таком входе и как если место перехода есть вложеная функция ,ну и куда возвращатся )

а конкретный «выход из середины» который вполне структурен - так как совмещён с прекращением функции.

имхо «эвристика» ценее тем кто не «с молоком матери» знаком с идеей стековой организации обратотки функций - и поэтому интерпретирует return как вычисляемый goto на адресс снятый с вершины стека( магазина)

т.е лично мне для которого замыкания (кактусы стека) - были усвоенна на много лет (десятилетие?) позже «текстовой» подстановки - которая сразу была свёрнута на стековую ибо если последовательно применять «текстовую подстановку» вылазят аргументы по именам от которых отказались в виду сложности(дороговизны относительно плодов) реализации.

в том специалист отличается от неофита - он(в идеале) понимает и осознаёт границы применимости того/иного инструмента.

закрываться авторитетом Дейкстры тут не продуктивно - если есть возможность укажи на место у Дейкстры где он касается выхода из середины функции

зы. лично мне нравятся циклы с выходом из середины.

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

Ерунда. Это проблемы кривого проектирования не читавших SICP персонажей.

Какой, к чёрту, SICP? Я говорил про Си. И этот паттерн применим только для Си. Здесь нет деструкторов; если где-то есть fopen(), то надо написать fclose(), руками и желательно в той же функции. Здесь нет with-open-file, которой можно удобно передать любое замыкание и вернуть любой результат.

ilammy ★★★
()

Функция выделения пятимерного массива, язык СИ:

#define I1   70
#define I2   70
#define I3   70
#define I4   70
#define I5   3


//--------------------- morfey_metka_malloc ------------------------

int***** morfey_metka_malloc()
{
    int *****arr;
    int i1=-1, i2=-1, i3=-1, i4=-1;

    arr=(int*****)malloc(I1*sizeof(int****));
    if(arr==NULL) return(NULL);
    for(i1=0; i1<I1; i1++){
        arr[i1]=(int****)malloc(I2*sizeof(int***));
        if(arr[i1]==NULL){ i1--; goto ERR;}
        for(i2=0; i2<I2; i2++){
            arr[i1][i2]=(int***)malloc(I3*sizeof(int**));
            if(arr[i1][i2]==NULL){ i2--; goto ERR;}
            for(i3=0; i3<I3; i3++){
                arr[i1][i2][i3]=(int**)malloc(I4*sizeof(int*));
                if(arr[i1][i2][i3]==NULL){ i3--; goto ERR;}
                for(i4=0; i4<I4; i4++){
                    arr[i1][i2][i3][i4]=(int*)malloc(I5*sizeof(int));
                    if(arr[i1][i2][i3][i4]==NULL){ i4--; goto ERR;}
                }
            }
        }
    }
    return(arr);

ERR:
    if(i2>=I2) i2--;
    if(i3>=I3) i3--;
    if(i4>=I4) i4--;
    for(;i1>=0; i1--){
        for(;i2>=0; i2--){
            for(;i3>=0; i3--){
                for(;i4>=0; i4--){
                    free(arr[i1][i2][i3][i4]);
                }
                i4=I4-1;
                free(arr[i1][i2][i3]);
            }
            i3=I3-1;
            free(arr[i1][i2]);
        }
        i2=I2-1;
        free(arr[i1]);
    }
    free(arr);
    return(NULL);
}

oleg_2
()
Ответ на: комментарий от ilammy

теорему Бёма—Якопини

дык они же и не требовали ограничиватся, показана была достаточность и равномощность их набора VS вычисляемый goto

верящие в теорему ...

экономия на понимании в такие побочки и выливается.

break /continue на меченый цикл вполне «культурно»

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

Когда я был на первом курсе, тоже так выделял память под многомерные массивы.

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

Мне настолько лень возится с многомерными массивами, что даже на убогой lua я навертел эмуляцию многомерного массива одномерным. А нас сях в универе иначе как одномерным и не делал.

Deleted
()
Ответ на: комментарий от beastie

beastie
=Количество ошибок в этом примере даже не хочется перечислять.=

Не настаиваю, но всё же интересно узнать, в порядке оказания
помощи профессионала любителю.

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

Я не профессионал. ☺ Начнём хотябы с того, что одного malloc более чем достаточно. Поведение в секции ERR: доверия тоже не вызывает.

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

а конкретный «выход из середины» который вполне структурен - так как совмещён с прекращением функции.

Нет, не структурен. Это хорошо визуально видно на блок-схемах алгоритмов, которые похоже нынче не в моде более. Если рассматривать алгоритм структурно, то до goto и после него выделяются два разных блока на одном и том же уровне вложенности. Оператор goto между ними «ломает» естественный ход событий, так как интуитивно и подсознательно ожидается, что после первого блока должен исполняться второй. Поэтому код с goto в середине воспринимается хуже и в общем случае более тяжек для осознания. То есть при редактировании ты можешь легко допустить невнимательность и после goto засунуть код, который должен выполняться в любом случае. Есть математическое доказательство того, что любой алгоритм можно привести к виду, когда такой промежуточной точки не будет. Это и будет структурным кодом.

имхо «эвристика» ценее тем кто не «с молоком матери» знаком с идеей стековой организации обратотки функций - и поэтому интерпретирует return как вычисляемый goto на адресс снятый с вершины стека( магазина)

Это к FORT. В С, хотя про стек знать приходится, однако для использования в алгоритмах он скрыт реализацией, и это правильно.

закрываться авторитетом Дейкстры тут не продуктивно - если есть возможность укажи на место у Дейкстры где он касается выхода из середины функции

Нехорошо передёргивать. Я не закрываюсь авторитетом Дейкстры, а аппелирую к изложенным им аргументам.

auto12884839
()
Ответ на: комментарий от oleg_2

любителю от любителя

уж если развлекатся с сборкой многомерного(N+1) из K N-мерных

то техничней реализовать рекурсией с вараргами когда

если аргумент один выделили вектор размера величины аргумента и вернули указатель //иначе выделили вектор указателей и в цикле заполнили рекурсивыными вызовами без 1 аргумента.

в итоге имеем дерево- и процедуру отведения памяти массиву произвольной размерности и произвольных допустимых линейных габоритов.

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

в том и закавыка - пока не перепрочитал Дейктстру(хоть и в переводе на русском) - у эпигонов его мысли о гоуту были очень и очень превратно «упрощены»

поэтому приведи аргументы предметно pls.

и тот же Дейкстра различал готу различной универсальности - для которых в «современных» языках есть отдельные ключевые слова.

Нет, не структурен.

нафига тут религосрач?

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

Какой, к чёрту, SICP? Я говорил про Си.

Ты сюда напотроллить забежал или как? SICP самые базовые вещи объясняет, без привязки к языку. То, что там в примерах используется схема - ну так какой-то яп надо было взять. Ты хотя бы название книги прочитай и обдумай.

И этот паттерн применим только для Си. Здесь нет деструкторов; если где-то есть fopen(), то надо написать fclose(), руками и желательно в той же функции. Здесь нет with-open-file, которой можно удобно передать любое замыкание и вернуть любой результат.

ORLY? Вообще-то есть.

int with_open_file(char * fname, int (*fn)(FILE*,void*), void*opaque) {
  FILE*f = fopen(fname);
  int r;
  assert(f);
  r=fn(f,opaque);
  fclose(f);
  return r;
auto12884839
()
Ответ на: комментарий от auto12884839

Увидь параллель

функция — блок с аргументами

выход из середины кольцевого(циклического) блока — return в произвольном месте функции

у того же Дейкстры вроде было кольцо со сторожами как универсальная структура для произвольного цикла.

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

ORLY? Вообще-то есть.

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

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

Массив большой, много памяти занимает, цельно не выделятя.
По заданию доступ к элементам должен быть обыкновенным индексным:
morfey_metka[1][1][1][1][1]=32;
Функция тщательно протестена на предмет освобождения памяти.
Для теста применял специальные обертки для malloc и free с
запоминанием и стиранием указателей в специальном массиве.
Чтоб все указатели отработали с free один-единственный раз.
В разных местах эти обертки по счетчику выдавали NULL, и в
середине цикла, и на «краях» цикла.

Вот qulinxao ниже Вашего сообщения предложил рекурсию.
При случае попробую, что получится, может он прав.

oleg_2
()
Ответ на: комментарий от qulinxao

в том и закавыка - пока не перепрочитал Дейктстру(хоть и в переводе на русском) - у эпигонов его мысли о гоуту были очень и очень превратно «упрощены»

Ты посмотри в каком годе он это выразился.

и тот же Дейкстра различал готу различной универсальности - для которых в «современных» языках есть отдельные ключевые слова.

Поэтому и есть, чтобы неразборчиво goto не пользовать. for, if, while - это всё структурированные аналоги goto, которыми не то, что можно обойтись, но если обходиться, жись становится намного проще.

нафига тут религосрач?

не знаю, тебе решать.

auto12884839
()
Ответ на: комментарий от ilammy

И стоит задуматься о предвыделении этого мегамассива на 300 метров в самом начале выполнения программы.

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

qulinxao
=техничней реализовать рекурсией=

Рекурсию я не догадался, наверно проще будет, при случае
попробую. Спасибо.

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

По заданию доступ к элементам должен быть обыкновенным индексным:

А уродский стиль кодирования - это тоже часть задания?

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

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

Ну поэтому его так часто используют. Если серьёзно, то SICP для этого и нужен, чтобы представлять себе в коде структуру, тот же самый with-open-file, только в отдельно взятых языках, позволяющих более разнообразные действия, ставить в конце воображаемого блока with-open-file оператор fclose вручную и понимать зачем это делается. Тогда и goto из середины цикла просто не понадобится.

Спасибо

Наздоровье. Тот кусок кода я опубликовал под GPLv3, пользуйся.

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

http://www.vspu.ac.ru/~chul/dijkstra/goto/goto.htm

1968

- имхо с фобией на гоуту повторилась история которая видимо характерна вообще для человечества

умный человек предложил эвристику . . . . клуши-воспитатели сформировали религию «что угодно лиш бы не гоуту»

и в его гоуту признано вредным (ща перепрочитал) не увидел запрета на ретурн из функции из более чем одного места.

qulinxao ★★☆
()
Ответ на: http://www.vspu.ac.ru/~chul/dijkstra/goto/goto.htm от qulinxao

1968

Вот и учти, какие на то время были ЯП:

http://www.pfnp.me/wp-content/uploads/2012/11/tongues-programming-languages-h...

В них возможностей было минимум. Ещё раз повторяю, возьми сколько-нибудь сложный код на том же Fortran IV и посмотри.

- имхо с фобией на гоуту повторилась история которая видимо характерна вообще для человечества

Это называется не фобия, а эволюция ЯП. Из аморфного goto отпочковались реально нужные структурированные операторы ветвления, которые принудительно структурируют код, хочешь ты этого или нет.

и в его гоуту признано вредным (ща перепрочитал) не увидел запрета на ретурн из функции из более чем одного места.

На то время его и быть не могло, потому что без goto вообще тогда никак. Да и сейчас он иногда вполне уместен, по ситуации. Например №1 ТС'а вполне годен.

auto12884839
()
Ответ на: комментарий от UVV

Ну сам я использую вариант 1, просто перечислил все варианты, которые встречал =)

Уже вспомнил, где встречал номер 2? Хотелось бы посмотреть, насколько известны его авторы.

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

Рекурсию я не догадался, наверно проще будет, при случае

попробую. Спасибо.

Через рекурсию конкретно то, что ты пытался сделать конечно элементарно будет. К сожалению рекурсия не всегда доступна из-за размеров стека, а хвостовая не везде есть. Вот обычный безрекурсивный способ, просто вариант, позабавиться:

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

#define NCL 5

#define I1   70
#define I2   70
#define I3   70
#define I4   70
#define I5   3

int spawn (int * src, const int * lim, int * cl) {
        int k = *cl;
        while ((k >= 0) && (++src [k] >= lim [k])) {
                src [k] = 0;
                k--;
        }
        return k >= 0;
}

int unspawn (int * src, const int * lim, int * cl) {
        int k = *cl;
        while ((k >= 0) && (--src [k] < 0)) {
                src [k] = lim [k] - 1;
                k--;
        }
        return k >= 0;
}

int main (int argc, char * argv []) {
        const int lim [5] = {I1, I2, I3, I4, I5};
        int idx [5] = {0, 0, 0, 0, 0};
        int i, e, cl;
        int ***** a;
        void ** q;
//      int flt [4] = {2, 1, 0, 1}; // точка искуственно вызванного сбоя, для теста
//      int k, f;
        int i0, i1, i2, i3;

        cl = 0;
        e = NULL == (a = calloc (lim [0], sizeof (void*)));
        do {
                q = (void **) a;
                for (i = 0; i <= cl && !e; i++) {
                        if (i == cl) {
                                e = NULL == (q [idx [i]] = calloc (lim [i+1], ((NCL - 2 == cl) ? sizeof (int) : sizeof (void*))));
                                printf ("+%d %p", idx [i], q [idx [i]]);
                                // искуственно создаём сбой выделения в выбранной точке, тестируем
/*
                                f = 1;
                                for (k = 0; (k < 4) && f; k++) f = f && (idx [k] == flt [k]);
                                if (f) {
                                        printf ("\n\nfault!\n\n");
                                        free (q [idx[i]]);
                                        e = 1;
                                        q [idx [i]] = NULL;
                                }
*/
                        } else {
                                q = (void **) q [idx [i]];
                                printf ("%d ", idx [i]);
                        }   
                }   
                if (!e) {
                        printf (", cl = %d\n", cl);
                        if (!spawn (idx, lim, &cl)) cl++;
                }
        } while (cl < NCL - 1 && !e);

        if (e) {
                if (!unspawn (idx, lim, &cl)) cl--;
                do {
                        q = (void **) a;
                        for (i = 0; i <= cl; i++) {
                                if (i == cl) {
                                        printf ("-%d %p", idx [i], q [idx [i]]);
                                        free (q [idx [i]]);
                                } else {
                                        q = (void **) q [idx [i]];
                                        printf ("%d ", idx [i]);
                                }
                        }
                        printf (": cl = %d\n", cl);
                        if (!unspawn (idx, lim, &cl)) cl--;
                } while (cl >= 0);
        }
       
        for (i0 = 0; i0 < lim [0]; i0++) {
                for (i1 = 0; i1 < lim [1]; i1++) {
                        for (i2 = 0; i2 < lim [2]; i2++) {
                                for (i3 = 0; i3 < lim [3]; i3++) {
printf ("%d %d %d %d %p\n", i0, i1, i2, i3, a [i0][i1][i2][i3]);
                                }
                        }
                }
        }
        return 0;
}

auto12884839
()

Обычно первый, если нужно делать cleanup — то часто третий.

theNamelessOne ★★★★★
()

на любой вкус:

1 - если нужно выделить ресурс поработать с ним и закрыть

2 - если нужно только добавить финализатор (возможно делать это только в случае исключения через onException)

3 - использование легких регионов, все действия (удаление выдененных объектов, очистка проводятся при выходе из региона, но не более одного раза, уменьшая нагрузку на gc.

foo1 = bracket createRes freeRes $ \res ->
        if ... 
            then a
            else b
  where createRes = ...
        freeRes   = ...
foo2 = (if ... then a else b) `finally` cleanup
foo3 :: (MonadResource m) => b -> m a
foo3 y = do
  register cleanupAction
  if ..
    then a
    else b

по теме в приведенных случаях 1 или 3.

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

Чисто мое имхо:

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

Перед выделением памяти для массива указателей занулять его. Тогда не надо будет усложнять освобождение сохраняя индекс последнего выделенного элемента.

Для выделения и освобождения памяти написать простые рекурсивные функции. Освобождение вообще тривиально — передаем void* и количество измерений. Для выделения передаем массив размерностей и количество измерений. Будут простые функции из нескольких строк, в которых разобраться будет куда проще.

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

Это называется не фобия, а эволюция ЯП. Из аморфного goto отпочковались реально нужные структурированные операторы ветвления, которые принудительно структурируют код, хочешь ты этого или нет.

Но никто же не доказал, что эти «отпочковавшиеся goto» являются достаточными для практических задач. Нет, qulinxao здесь прав - получился очередной «глухой телефон» как в детской игре.

Более того, в языке с настоящими макросами (т.е. в динамически типизированном языке, ну, вы поняли, какое семейство языков я имею в виду, а не те новомодные языки, о которых забудут лет через десять - пятнадцать), goto просто необходим.

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

Функция выделения пятимерного массива, язык СИ:

Монстроузно. Лучше запихать выделение памяти на каждом этапе в отдельную функцию. Тогда в каждой функции вместо goto ERR можно будет писать просто небольшой сleanup и return. Код упростится т.к. cleanup и функция выделения подмассива будет общая. Т.к. malloc все равно работает медленно, то существенного снижения скорости вы не получите.

no-such-file ★★★★★
()
Ответ на: комментарий от oleg_2

вот тебе код, ни в чём себе не отказывай.

14:46:15 ~/C 14
$cat dynarr.c
#include <stdlib.h>
void * g_dynarr(char* sz){
	if(!sz[1]){
		return malloc(sz[0]*sizeof(int));
	}
	void** p=malloc(sz[0]*sizeof(void*));int i;
	for(i=0;i<sz[0];i++){
		p[i]=g_dynarr(sz+1);
	}
	return p;
}
int main(int c,char **a){
	char sz[]={2,3,4,5,255,0};//if short need +2 but ++;

	g_dynarr(sz);//bad_idia for g_dynarr(NULL) and g_dynarr("")

	return 0;
}
14:46:30 ~/C 15
$
qulinxao ★★☆
()
Последнее исправление: qulinxao (всего исправлений: 4)
Ответ на: комментарий от oleg_2

чистильщик (cl) - на домашку

$cat dynarr.c
#include <stdlib.h>
#include <stdio.h>
int g=0;
void* m_init(size_t t){
	int* a=(int*)malloc(t*sizeof(int));
	int i;
	for(i=0;i<t;i++){
	  a[i]=g++;
	}
	return a;
}
void * g_dynarr(char* sz){
	if(!sz[1]){
		 return m_init(sz[0]);//simple test

	}
	void**p=malloc(sz[0]*sizeof(void*));
	int i;for(i=0;i<sz[0];i++){
		p[i]=g_dynarr(sz+1);
	}
	return p;
}
void cl(void* a,char* sz){
	return ;
}
int main(int c,char **z){
	char sz[]={10,10,0,1,1,10,0};//if short need +2 but ++;

	int i,j,k,l,m,n;
	//int***** a=(int*****)g_dynarr(sz);//bad_idia for g_dynarr(NULL) and g_dynarr("")
	/* sz={1,2,3,4,5,10,0};
	   for(i=0;i<sz[0];i++){
		for(j=0;j<sz[1];j++){
			for(k=0;k<sz[2];k++){
				for(l=0;l<sz[3];k++){
					for(m=0;m<sz[4];m++){
						for(n=0;n<sz[5];n++){
							printf(" %d",a[i][j][k][l][m]);
						}
						printf("\n");
					}
				}
			}
		}
	}*/
	
	{//test 10x10
		int **a=(int**)g_dynarr(sz);
		for(i=0;i<sz[0];i++){
			for(j=0;j<sz[1];j++){
				printf(" %d",a[i][j]);
			}
			printf("\n");
		}
		cl(a,sz);
	}
	{//test 2x3x4;
		sz[0]=2;sz[1]=3;sz[2]=4;g=0;
		//sz[2]=10;
		sz[3]=0;
		int ***a=(int***)g_dynarr(sz);
		for(i=0;i<sz[0];i++){
			printf("plane %d\n",i);
			for(j=0;j<sz[1];j++){
				for(k=0;k<sz[2];k++){
					printf(" %d",a[i][j][k]);
				}
				printf("\n");
			}
		}
		cl(a,sz);
	}
	return 0;
	
}
qulinxao ★★☆
()

while(0);

Это же знаменитый метод циклического нуля, который создал молодой, но уже прославившейся автор методологии «совокупляющихся лямбда-гусей»

nerdogeek
()
Ответ на: вот тебе код, ни в чём себе не отказывай. от qulinxao

Вот это слабое место:

    for(i=0;i<sz[0];i++){
        p[i]=g_dynarr(sz+1);
    }
    return p;
Тогда так:
void * g_dynarr(char* sz){
    int err=0;
    if(!sz[1]){
        return malloc(sz[0]*sizeof(int));
    }
    void** p=malloc(sz[0]*sizeof(void*));int i;
    for(i=0;i<sz[0];i++){
        p[i]=g_dynarr(sz+1);
        if(p[i]==NULL){
            err=1;
            break;
        }
    }
    if(err){
        i--;
        for(;i>=0;i--) free(p[i]);
        free(p);
        p=NULL;
    }
    return p;
}

Вызывает беспокойство тип void, я стараюсь точно определять
типы, кстати, в моей фунции это отражено.
Вот если тип void не страшен, и auto12884839 и qulinxao показали,
как им пользоваться (и никто не возмутился), то согласен.

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

если ловить ошибку ( в процессе выделения - то её нужно «возвращать» -что бы не продолжать выделения а делать возврат уже выделеных деревьев).

для 6? уровневых массив предпочитают «фортран»

либо

telem a[]=(telem*)malloc(s0*s1*s2....*sN*sizeofelem);
a[(i*s1+j)*s2+k)*s3...+m]

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

Наверно так:

Вместо этого
for(;i>=0;i--) free(p[i]);

надо это
for(;i>=0;i--) free_dynarr(p[i]);
где free_dynarr() рекурсивная функция освобождения.

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

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

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

ошибка (может) возникает в подузле поэтому р - должно быть корневым иначе освободится только успешные дети , а необходимо осободить всех уже выделеных.

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

«р - должно быть корневым иначе освободится только успешные дети , а необходимо осободить всех уже выделеных.»

Да, так. Вот на основе Вашей заготовки придумал:

void free_dynarr(void* p, char* sz){
    if(!sz[1]){
        free((int*)p);
        return;
    }
    for(i=0;i<sz[0];i++){
        free_dynarr(p[i], sz+1);
    }
    return;
}

void * g_dynarr(char* sz){
    int err=0;
    if(!sz[1]){
        return malloc(sz[0]*sizeof(int));
    }
    void** p=malloc(sz[0]*sizeof(void*));int i;
    for(i=0;i<sz[0];i++){
        p[i]=g_dynarr(sz+1);
        if(p[i]==NULL){
            err=1;
            break;
        }
    }
    if(err){
        i--;
        for(;i>=0;i--) free_dynarr(p[i], sz+1);
        free(p);
        p=NULL;
    }
    return p;
}
Вроде должно работать. Про типы никто ничего не пишет, а раньше спорили и ругались. Вот это free((int*)p);

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