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;
}

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

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

:(

представь корень это прадед

часть правнуков от старших детей успешно выделилось

на внуке (2 сын младшего сына ) маллок передал привет -нет больше памяти. в ветке if(err) успешно освободится 1сын и его потомки - однако для освобождения двоюродных родственников (сбойкого внука) у тя просто нет кода .

ps. спасибо за напоминание своим примером , что рекурсия это матан.

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

Если надо освобождать ресурсы - 3.

ресурсы можно выделить и освободить во внешней функции.

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

т.е какие реальные ограничения реализации делали полезной такую эвристику.

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

drBatty ★★
()

У вас в мозгу срабатывает переключатель, когда вы видете goto?

да. Ибо goto ломает структуру программы.

(Но фобии у меня нет, в pure C goto иногда полезно, и я его применяю).

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

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

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

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

ничего не мешает тебе выделить свой массив, но вместо goto ERR писать просто return.

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

Проблем со скоростью не будет, дополнительных проверок - тоже. keep it simple, stupid

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

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

ИМХО это копеечная плата за то, что я явно вижу, где у меня ресурс выделяется, где обрабатывается, а где освобождается. Всего 3 строки на 3 действия. А держать в памяти паутину макарон из goto мне лень.

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

№1 годно. Остальное быдлокод.

Ибо goto ломает структуру программы.

(Но фобии у меня нет, в pure C goto иногда полезно, и я его применяю).

Так №3 и есть тот шаблон, который полезен. А какой же ты применяешь?

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

Про типы никто ничего не пишет, а раньше спорили и ругались.

Кто посмел? Наверное они прочитали про CLOS и мультиметоды, и теперь с позором удалились, устыдившись своего жалкого вида.

Вот это free((int*)p);

Я вообще не понимаю, зачем тут typecast. Функция free всё равно void* освобождать будет.

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

Так №3 и есть тот шаблон, который полезен. А какой же ты применяешь?

не. Это просто. ИМХО тут return уместен. Может быть в цикле нужно goto. Короче - если проще с goto, то надо с goto. Но это очень редко бывает. Обычно с goto только хуже.

drBatty ★★
()
Последнее исправление: drBatty (всего исправлений: 1)
Ответ на: комментарий от dave

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

Жертва Фурсенки обнаружена. Это по-твоему что как не доказательство?

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

Примеры последуют?

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

Ах да, и про необходимость goto в одном семействе языков на букву Л мне тоже интересно будет услышать.

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

Там было про «практические задачи». А та теорема сродни теореме существования. Иногда от нее ни холодно, ни жарко.

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

Не путай теорию с практикой.

Не путай практику, прислушивающуюся к голосу разума (aka теории) и свою суровую реальность, в которой любому наркоману «на практике» нужна доза, и в которой даже более того, находят «практическое» применение с поддержкой соответствующих спонсоров даже такой штуке как Python.

auto12884839
()

это надо было назвать найди лишний вариант
третий - лишний

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

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

А если речь идёт, например, о файловых дескрипторах? Дело не в memory management, а в resource management вообще.

true_admin ★★★★★
()

предпочитаю первый, а второй вариант - когда надо что-то деинициализировать в конце работы

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от qulinxao

Протестил Вашу программу - работает. Приведу ее с тестовой частью:

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>

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


// Глобальные переменные для тестовых оберток.
void* test[1000];
int test_ind_max = 0; // число удачных вызовов malloc()
int test_ind     = 0; // счетчик вызовов malloc()

// ТЕСТОВЫЕ ОБЕРТКИ

//----------------- init_Malloc --------------------------

void init_Malloc(void **test, int Stest)
{
    int i;
    for(i=0; i<Stest; i++){
        test[i] = NULL;
    }
    test_ind = 0;
    return;
}

//----------------------- free_cntl --------------------------------
// проверка на освобождение всей памяти
int free_cntl(void **test, int Stest)
{
    int i;
    for(i=0; i<Stest; i++){
        if(test[i] != NULL) printf("ERROR: free_cntl: test[%d] != NULL\n", i);
    }
    printf("RETURN: free_cntl:\n");
    return;
}

//-------------------- poisk_ptr ---------------------------
// поиск указателя в массиве
int poisk_ptr(void *p, void **test, int Stest)
{
    int i;
    for(i=0; i < Stest; i++){
        if(test[i] == p) break;
    }
    if(i>=Stest) return(-1);
    return(i);
}

//------------------------ Malloc ------------------------------

void *Malloc(int size)
{
    void *p;

    if(test_ind >= test_ind_max) return(NULL);
    p=malloc(size);
    if(p==NULL) return(NULL);
    test[test_ind] = p;
    test_ind++;
    return(p);
}

//---------------------- Free -------------------------

void Free(void *p)
{
    int i;

    if(p==NULL) printf("ERROR: Free: t1: p==NULL\n");

    i=poisk_ptr(p, test, test_ind);
    if(i<0){ printf("ERROR: Free: t2: i=poisk_ptr(%p)<0\n", p); return;}
    free(p);
    test[i] = NULL;
    return;
}

// ОСНОВНАЯ ПРОГРАММА

//------------------ dynarr_free -------------------------

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

//-------------------- dynarr_malloc ---------------------------------

void * dynarr_malloc(char* sz){
    int i, err=0;
    void **p;

    if(!sz[1]){
        return(Malloc(sz[0]*sizeof(int)));
    }
    p=Malloc(sz[0]*sizeof(void*));
    if(p==NULL) return(NULL);
    for(i=0; err==0 && i<sz[0];i++){
        p[i]=dynarr_malloc(sz+1);
        if(p[i]==NULL){
            err=1;
            break;
        }
    }
    if(err){
        i--;
        //i--; // если это i--; раскомментировать, то выдает неосвобожденную память.
        for(;i>=0;i--) dynarr_free(p[i], sz+1);
        Free(p);
        return(NULL);
    }
    return p;
}

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

int *****morfey_metka_malloc()
{
    char sz[6];
    sz[0]=I1;
    sz[1]=I2;
    sz[2]=I3;
    sz[3]=I4;
    sz[4]=I5;
    sz[5]=0;
    return(dynarr_malloc(sz));
}

//------------------- morfey_metka_free ---------------------

void morfey_metka_free(int *****p)
{
    char sz[6];
    sz[0]=I1;
    sz[1]=I2;
    sz[2]=I3;
    sz[3]=I4;
    sz[4]=I5;
    sz[5]=0;
    dynarr_free((void**)p, sz);
    return;
}

//----------------------- main --------------------------

int main()
{
    int***** morfey_metka;

    // в цикле перевыделяю массив с разными точками ошибки
    for(test_ind_max = 121; test_ind_max>=80; test_ind_max--){
    //for(test_ind_max=80; test_ind_max>=40; test_ind_max--){
    //for(test_ind_max=40; test_ind_max>=0; test_ind_max--){
        printf("\n");
        printf(">>>>>>>>>>>>>>> test_ind_max=%d\n", test_ind_max);
        init_Malloc(test, sizeof(test)/sizeof(void*));

        morfey_metka=morfey_metka_malloc();
        if(morfey_metka==NULL){
            printf("ERROR: morfey_metka=NULL\n");
            free_cntl(test, test_ind_max);
            continue;
        }
        morfey_metka[1][1][1][1][1]=32;
        morfey_metka[1][1][1][1][2]=33;
        printf("morfey_metka[1][1][1][1][1]=%d\n", morfey_metka[1][1][1][1][1]);
        printf("morfey_metka[1][1][1][1][2]=%d\n", morfey_metka[1][1][1][1][2]);

        morfey_metka_free(morfey_metka);
        free_cntl(test, test_ind_max);
    }
    exit(0);
}
Задача-то конкретная, «интерфейс» функций не разрешат менять.
И кто-нибудь ответте, когда приводим тип, как в этом примере,
то это только для ублажения компилятора, или могут быть плохие
последствия?

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

А что не так?
Ну посмотрите две функции:
void dynarr_free(void **p, char* sz)
void * dynarr_malloc(char* sz)
Ну Вы же сами их предложили, на остальное можно не
обращать внимания, это тест на освобождение памяти.

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

Обосновывая это чем?

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

принеси пользу обществу . прекрати(на время) программировать. начни с азов. ...

void * dynarr_malloc(char* sz){
    int i;
    void **p;

    if(!sz[1]){
        return(Malloc(sz[0]*sizeof(int)));
    }
    p=Malloc(sz[0]*sizeof(void*));
    for(i=0;(p!=NULL)&&i<sz[0];i++){//(p!=NULL is p)
        p[i]=dynarr_malloc(sz+1);
        if(p[i]!=NULL)continue;
            //зачемммм? Free(null) есть ошибка а не игнор и выход??
            if(i>0)do{dynarr_free(p[--i], sz+1);}while(i);
            //i++;while(i--){dynarr_free(p[i],sz+1;}//this (line alter for upper line) work only if Free(NULL) is : if(p==NULL){....;return NULL; }
            p=Free(p);//if void. Free(&p) where void Free(void** p) {.... p=Null;return}
    }
    return p;
}


int poisk_ptr(void *p, void **test, int Stest)
{
    int i;
    for(i=0; i < Stest; i++){
        if(test[i] == p) return i;
    }
    return(-1);
}

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

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

Это тест.
Есть две функции, они протестены, меняем в них
Malloc и Free на malloc и free и готово.
Вот они в чистом рабочем виде:

//------------------ dynarr_free -------------------------

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

//-------------------- dynarr_malloc ---------------------------------

void * dynarr_malloc(char* sz){
    int i, err=0;
    void **p;

    if(!sz[1]){
        return(malloc(sz[0]*sizeof(int)));
    }
    p=malloc(sz[0]*sizeof(void*));
    if(p==NULL) return(NULL);
    for(i=0; err==0 && i<sz[0];i++){
        p[i]=dynarr_malloc(sz+1);
        if(p[i]==NULL){
            err=1;
            break;
        }
    }
    if(err){
        i--;
        for(;i>=0;i--) dynarr_free(p[i], sz+1);
        free(p);
        return(NULL);
    }
    return p;
}

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

continue

т.е как в ассемблере линеаризация ветвей вынуждает помещать jmp в конце ветвей так и у Вас прикручивание флагов для дальнейшего ветвления - при чём можно на месте установки флага уже делать clean_up и полный выход, без загроможнения штатного пути.

qulinxao ★★☆
()
Ответ на: continue от qulinxao

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

«можно на месте установки флага уже делать clean_up и полный выход»
Согласен, можно.
Снова боюсь Вас прогневить, но я люблю и goto, но спориь не буду.

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

:)

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

Снова боюсь Вас прогневить

трепещите

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

Я пишу только небольшие СИ-программы и отдельные СИ-функции.
Мне задали именно такой массив и именно с таким «интерфейсом»,
т. е. с #define-ами. Доступ к элементам по индексам. Я даже
не знаю, о чем вся остальная программа, не показывают.

oleg_2
()

1ый. В чистой сишечке нормально отношусь к 3ему, но предпочитаю для закрытия ресурсов вложенные if'ы:

int
fun(/*...*/)
{
    int rc = MYRC_OK;
    res1_t res1 = res1_acquire();
    if (res1) {
        res2_r res2 = res2_acquire();
        if (res2) {

            /* ... */

            res2_release(res2);
        }
        else {
            rc = MYRC_ERR2;
        }
        res1_release(res1);
    }
    else {
        rc = MYRC_ERR1;
    }
    return rc;
}

А если только свои подсистемы, то примерно так выходит:

int
fun(/*...*/)
{
    res1_t res1;

    int rc = res1_acquire(&res1);

    if (rc == MYRC_OK) {

        res2_t res2;
        rc = res2_acquire(&res2);

        if (rc == MYRC_OK) {

            /*...*/

            res2_release(&res2);
        }
        res1_release(&res1);
    }
    return rc;
}

forCe
()

Кстати, раз уж тут присутствуют любители Дейкстры, то может кто-то пояснит мне смысл и полезность «цикла Дейкстры», а может заодно и «паука»?

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

Ты посмотри, что ты натворил!

void init_Malloc(void **test, int Stest)

Открой для себя man calloc.

Задача-то конкретная, «интерфейс» функций не разрешат менять.

Только точек входа, а static менять твоё дело и твоё право.

И кто-нибудь ответте, когда приводим тип, как в этом примере,

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

Никаких, и без этого никак иногда. Главное, чтобы сам знал, что и зачем делается.

Для проверки лучше использовать список. Самодельный или из glib например. Варианты с перебором массива не годятся, потому что какой-то указатель в массиве может быть по ошибке затёрт. При выделении заноси указатель в список, а при удалении делай поиск по списку, проверь что такой там есть и он там один, а на выходе проверь что список пуст. Этот же метод можно использовать и для непосредственно решения задачи, удалять указатели из списка при сбое выделения, если конечно не жалко озы под 70*70*70*3 элементов списка.

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