Thread: Problem with free()

  1. #1
    Registered User
    Join Date
    Sep 2011
    Posts
    78

    Problem with free()

    Hello!

    This is the problem: when I try to delete all the elements of a linked list the program returns an error while it doesn't when I do the same with only one element of the list.

    Here's the code:

    Code:
    typedef struct my_articolo
    {
        signed int code;
        char *name;
        char *des;
        float price;
        signed int q_disp;
        signed int q_min;
        struct my_articolo *n;
    } articolo;
    
    articolo *start = 0;
    
    
    
    void add()
    {
        articolo *p = 0, *c = 0, *nn = calloc(1, sizeof(articolo));
        char *n_name = (char*) calloc(NAME_LENGTH, sizeof(char)), *n_des = (char*) calloc(DES_LENGTH, sizeof(char));
    
        if(!nn)
        {
            fputs("\nErrore di memoria. Impossibile aggiungere l'articolo.\n", stderr);
            free(nn);
            return;
        }
    
    i_code:
        fputs("\nInserisci il codice del componente (0 - 99999999): ", stderr);
        fflush(stdin);
        scanf("%8i", &nn->code);
    
        if(nn->code < 0 || nn->code > 99999999)
        {
            fputs("\nIl codice inserito non e' valido.\n", stderr);
            goto i_code;
        }
    
        for(c = start, p = 0; c && nn->code > c->code; p = c, c = c->n);
    
        if(c && (nn->code == c->code))
        {
            fputs("\nL'articolo esiste gia'. Impossibile aggiungerlo.\n", stderr);
            free(nn);
            return;
        }
    
    i_name:
        fputs("Inserisci il nome dell'articolo: ", stderr);
        r_line(n_name, NAME_LENGTH, stdin);
    
        if(strlen(n_name) <= 0)
        {
            fputs("\nIl nome inserito non e' valido.\n", stderr);
            goto i_name;
        }
    
        nn->name = n_name;
    
    
    i_des:
        fputs("Inserisci la descrizione dell'articolo: ", stderr);
        r_line(n_des, DES_LENGTH, stdin);
    
        if(strlen(n_des) <= 0)
        {
            fputs("\nLa descrizione inserita non e' valida.\n", stderr);
            goto i_des;
        }
    
        nn->des = n_des;
    
    
    i_price:
        fputs("Inserisci il prezzo dell'articolo(0 - 9999999.99): ", stderr);
        fflush(stdin);
        scanf("%7f", &nn->price);
    
        if(nn->price < 0.0 || nn->price > 9999999.99)
        {
            fputs("\nIl prezzo inserito non e' valido.\n", stderr);
            goto i_price;
        }
    
    
    i_disp:
        fputs("Inserisci la disponibilita' dell'articolo(0 - 9999999): ", stderr);
        fflush(stdin);
        scanf("%7i", &nn->q_disp);
    
        if(nn->q_disp < 0 || nn->q_disp > 9999999)
        {
            fputs("\nIl valore inserito non e' valido.\n", stderr);
            goto i_disp;
        }
    
    
    i_min:
        fputs("Inserisci la quantita' minima di riordino(0 - 9999998): ", stderr);
        fflush(stdin);
        scanf("%7i", &nn->q_min);
    
        if(nn->q_min < 0 || nn->q_min > 9999998)
        {
            fputs("\nIl valore inserito non e' valido.\n", stderr);
            goto i_min;
        }
    
        nn->n = c;
    
        if(!p)
        {
            start = nn;
        }
        else
        {
            p->n = nn;
        }
    }
    
    
    
    void delete()
    {
        articolo *p = 0, *c = 0;
        signed int code = 0, c_code = 0;
    
        if(!start)
        {
            fputs("\nDatabase vuoto.\n", stderr);
            return;
        }
    
    menu_e:
        fputs("\n1 - Elimina uno o piu' componenti\n", stderr);
        fputs("\n2 - Elimina tutto il database\n", stderr);
        fputs("\n3 - Torna al menu'\n", stderr);
        fputs("\nInserisci il codice corrispondente alla tua scelta: ", stderr);
    
        fflush(stdin);
        scanf("%u", &c_code);
    
        switch(c_code)
        {
        case 1:
    del:
            fputs("\nInserisci il codice del componente: ", stderr);
    
            fflush(stdin);
            scanf("%u", &code);
    
            for(c = start, p = 0; c && (c->code != code); p = c, c = c->n);
    
            if(!c)
            {
                fputs("\nComponente non trovato. Impossibile completare la cancellazione.\n", stderr);
                fputs("\nRiprovare?[s/n]: ", stderr);
                fflush(stdin);
                if(fgetc(stdin) == 's')
                {
                    PUTS_LINE_STDERR;
                    goto del;
                }
                goto ask_e;
            }
            if(!p)
            {
                start = c->n;
            }
            else
            {
                p->n = c->n;
            }
    
            free(c->name);
            free(c->des);
            free(c);
    
            fputs("\nComponente eliminato.\n", stderr);
            break;
    
        case 2:
            for(c = start, p = 0; c; p = c, c = c->n);
            {
                free(c->name);
                free(c->des);
                free(c);
            }
    
            start = 0;
    
            fputs("\nDatabase svuotato.\n", stderr);
            return;
    
        case 3:
            return;
    
        default:
            fputs("\nIl codice inserito non e' valido.\n", stderr);
            PUTS_LINE_STDERR
            goto menu_e;
            break;
        }
    
    ask_e:
        fputs("\nContinuare con le eliminazioni?[s/n]: ", stderr);
        fflush(stdin);
        if(fgetc(stdin) == 's')
        {
            PUTS_LINE_STDERR;
            goto menu_e;
        }
    }
    In delete() the case 1 works but the case 2 returns an error. Any suggestion?

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Does r_line acquire memory via malloc? Otherwise, that memory is not yours to free.

    Also, once you have done free(c), there's no way you can do c = c->n (since c->n doesn't exist any longer). You will have to store that somewhere before you free c.

  3. #3
    Registered User
    Join Date
    Sep 2011
    Posts
    78
    Code:
    char *n_name = (char*) calloc(NAME_LENGTH, sizeof(char)), *n_des = (char*) calloc(DES_LENGTH, sizeof(char));
    Your second correction is true but the for fails at the first cicle.

  4. #4
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by drew99 View Post
    Code:
    char *n_name = (char*) calloc(NAME_LENGTH, sizeof(char)), *n_des = (char*) calloc(DES_LENGTH, sizeof(char));
    Your second correction is true but the for fails at the first cicle.
    If you trust r_line to not overwrite that, then great. (EDIT: And looking at the code again, I suspect it can't, which is good.) I would suggest then running your program in a debugger and/or using valgrind to pinpoint what exactly is going wrong and why.

  5. #5
    Registered User
    Join Date
    Jun 2010
    Location
    Michigan, USA
    Posts
    143
    [Removed]
    Last edited by pheininger; 12-08-2013 at 12:58 PM. Reason: Decided not relevant.

  6. #6
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Ouch! Actual, real-life spaghetti code! Rare to see these days.
    What possessed you to use gotos all over the place?

    At this point, the best remedy is to print the code out, delete the file, then burn the printout while repeating "I will not use gotos, I will not use gotos, ...".

    Then rewrite the code from scratch.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  7. #7
    Registered User
    Join Date
    Nov 2012
    Posts
    1,393
    forget goto. what is fflush(stdin)? I never understood why people write that.

  8. #8
    Registered User
    Join Date
    Sep 2011
    Posts
    78
    Thanks to all, but what are the alternatives for goto and how can I resolve the problem with free()?

  9. #9
    Registered User
    Join Date
    Nov 2012
    Posts
    1,393
    What is the value of c when you go into case 2? Also what is the purpose of p in the for loop:

    Code:
            for(c = start, p = 0; c; p = c, c = c->n);
            {
                free(c->name);
                free(c->des);
                free(c);
            }
    You might have an easier time if you break this thing up into smaller pieces. You should be handling the user input somewhere else, and then write a few individual functions to add and delete elements from the list.

  10. #10
    Registered User
    Join Date
    Sep 2011
    Posts
    78
    Ok:

    Code:
    for(p = start, c = 0; p; p = c);
            {
                c = p->n;
                free(p->name);
                free(p->des);
                free(p);
            }

  11. #11
    Registered User
    Join Date
    Sep 2011
    Posts
    78
    I've done more test and I've found that the program returns an error when I try to delete the first element of the list, so the case 2 can't work!
    How is it possible that the program doesn't allow me to delete the first element of the linked list?
    Last edited by drew99; 12-08-2013 at 03:49 PM.

  12. #12
    Registered User
    Join Date
    Sep 2011
    Posts
    78
    Quote Originally Posted by oogabooga View Post
    Ouch! Actual, real-life spaghetti code! Rare to see these days.
    What possessed you to use gotos all over the place?

    At this point, the best remedy is to print the code out, delete the file, then burn the printout while repeating "I will not use gotos, I will not use gotos, ...".

    Then rewrite the code from scratch.
    Can you post a solution without gotos, thanks?

  13. #13
    Registered User
    Join Date
    Sep 2011
    Posts
    78
    Can you tell me what are the advantages of using cycles instead of goto?
    Looking at the assembly produced by isolating a small portion with a menu, there seems to be no substantial differences, even if I'm not very expert in ASM.

  14. #14
    Registered User
    Join Date
    Nov 2012
    Posts
    1,393
    Using a for loop or do while makes the intention clear; that's the advantage. Your goto and label pairs are basically for loops but without using "for". If you rewrite it that way, then it is less error prone and makes your intention clear.

    Of course, as you mention, it will end the end be converted into JMP or some equivalent. But if you wanted to program assembly directly, why bother with C in the first place.

  15. #15
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    who taught you to use goto anyway? there is no reputable tutorial on the web that teaches it. most don't even acknowledge that it exists.
    What can this strange device be?
    When I touch it, it gives forth a sound
    It's got wires that vibrate and give music
    What can this thing be that I found?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. problem with free()
    By klmdb in forum C Programming
    Replies: 3
    Last Post: 11-04-2011, 11:19 AM
  2. i have a problem with free();
    By nik2 in forum C Programming
    Replies: 12
    Last Post: 03-07-2010, 02:09 AM
  3. Problem with Free.
    By chakra in forum C Programming
    Replies: 9
    Last Post: 12-15-2008, 11:20 AM
  4. free() problem
    By audinue in forum C Programming
    Replies: 19
    Last Post: 07-19-2008, 11:18 PM
  5. buy one get one free problem
    By Nick_365 in forum C++ Programming
    Replies: 29
    Last Post: 02-12-2006, 02:17 AM