Search code examples
cstructstackdynamic-memory-allocationrealloc

Table of structures (realloc in C)


i am trying to write a code in C but i am having some problems with realloc. I had to write a code that will create a stack, and will add to it (dodaj_do_stosu), reamove from it (usun_ze_stosu) and will look at the top thing that is on this stack. I have problem with compiling(it does work for first two words but then it returns (0xC0000374)).

I think i am usining the realloc wrong and the sizeof my structure. If someone could look at my code (especially at the function (dodaj_do_stosu) and tell me what am i doing wrong thx. My code look like this:

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

typedef struct {
    int n;
    char *nazwa;
}element_t;

typedef struct {
    int rozmiar;
    element_t **tablica;
}stos_t;


void top_of_stack(stos_t *s){
    printf("ostatni element stosu:rozmiar = %d nazwa=%s, n=%d\n", s->rozmiar,                         s->tablica[s->rozmiar]->nazwa, s->tablica[s->rozmiar]->n);
}
void init(stos_t *s)
{
    s->rozmiar=0;
    s->tablica=malloc(0);
}

void dodaj_do_stosu(stos_t *s, int n, char *name)
{

    s->tablica = realloc(s->tablica, (s->rozmiar + 1) * sizeof(s->tablica));
    s->tablica[s->rozmiar]->nazwa = name;
    s->tablica[s->rozmiar]->n = n;
    printf("rozmiar=%d, n=%d , nazwa=%s\n",s->rozmiar, s->tablica[s->rozmiar]->n, s->tablica[s->rozmiar]->nazwa);
    s->rozmiar++;


}

void usun_ze_stosu(stos_t *s)
{
    s->tablica = realloc(s->tablica, (s->rozmiar - 1) * sizeof(s->tablica[0]));
    s->rozmiar--;
}

void rm(stos_t s)
{
    free(s.tablica);
}

int main(int argc, char **argv)
{
    stos_t s;
    init(&s);
    int i;
    srand(time(0));
    if (argc>1)
        for(i=1;i<argc;i++){
            printf("%s\n", argv[i]);
            dodaj_do_stosu(&s, rand() % 10, argv[i]);
        }
    for(i=0;i<argc-1;i++){
        //printf("i=%d, n=%d, nazwa=%s\n",i, s.tablica[i].n, s.tablica[i].nazwa);
    }

    //top_of_stack(&s);
    //usun_ze_stosu(&s);
    //top_of_stack(&s);
    rm(s);
    return 0;

}



Solution

  • At least the function dodaj_do_stosu is wrong. The data member tablica is declared like

    element_t **tablica;
    

    So the expression s->tablica[s->rozmiar] has the type element_t * and an indeterminate value. Thus dereferencing the pointer expression for example like

    s->tablica[s->rozmiar]->nazwa
    

    invokes undefined behavior.

    You have to allocate memory for objects of the structure type element_t not for pointers of the type element_t *.

    So you need to declare the data member like

    element_t *tablica;
    

    and within the function to write

    s->tablica = realloc(s->tablica, (s->rozmiar + 1) * sizeof( *s->tablica));
    

    Also it is safer to use an intermediate pointer for calls of realloc.

    The function can look the following way

    int dodaj_do_stosu( stos_t *s, int n, char *name )
    {
        element_t *tmp = realloc( s->tablica, ( s->rozmiar + 1 ) * sizeof( *s->tablica ) );
        int success = tmp != NULL;
    
        if ( success )
        {
            s->tablica = tmp; 
            s->tablica[s->rozmiar]->nazwa = name;
            s->tablica[s->rozmiar]->n = n;
            printf("rozmiar=%d, n=%d , nazwa=%s\n", s->rozmiar, s->tablica[s->rozmiar]->n, s->tablica[s->rozmiar]->nazwa );
            ++s->rozmiar;
        }
    
        return success;
    }
    

    Consequently the function should be redefined at least the following way. As is it can for example invoke undefined behavior when s->rozmiar is equal to 0.

    int usun_ze_stosu( stos_t *s )
    {
        int success = s->rozmiar != 0;
    
        if ( success )
        {
            element_t *tmp = realloc( s->tablica, ( s->rozmiar - 1 ) * sizeof( *s->tablica ) );
            success = tmp != NULL;
    
            if ( success )
            {
                s->tablica = tmp;
                --s->rozmiar;
            }
        }
    
        return success;
    }
    

    Also within the function init it will be much better ro write

    void init(stos_t *s)
    {
        s->rozmiar=0;
        s->tablica = NULL;
    }
    

    Another problem is the function rm

    void rm(stos_t s)
    {
        free(s.tablica);
    }
    

    You should pass the original object through a pointer to it and within the function to write

    void rm(stos_t *s)
    {
        free( s->tablica );
        s->tablica = NULL;
        s->rozmiar = 0;
    }