Home > Blockchain >  Table of structures (realloc in C)
Table of structures (realloc in C)

Time:12-02

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;

}


CodePudding user response:

A big part of your problem is that tablica is an array of pointers, but you never initialize the pointers themselves.

The dodaj_do_stosu function reallocates the array, but doesn't create the element_t objects. Therefore any dereference of e.g. s->tablica[s->rozmiar] will lead to undefined behavior.

There are two possible solutions:

  1. Allocate a new element_t structure:

    s->tablica[s->rozmiar] = malloc(sizeof(element_t));
    

    before you initialize the element_t structure members.

  2. Make tablica an array of structure objects instead of pointers:

    element_t *tablica;  // tablica is an array of objects, not an array of pointers
    

I recommend solution 2.

CodePudding user response:

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