BoobyTrap
BoobyTrap

Reputation: 978

C - realloc failure

I have a pointer issue probably but I can't figure out what is the problem with this. The project is supposed to read numbers from file(Works correctly) and then add the information into a dynamically allocated array.

This is part of the code for reading from the file and adding into the array: buffer[0] is a special character that marks that the next inputs will be for street array.

I have been looking through the code and changing stuff for about a week and still can't figure out where the problem is. Note that the first slot works fine, after I realloc for the second time it throws me an exception from inside "AddStreet" saying access violation writing location. I am sure it is something really stupid that I missed or failed to understand so any help would be appreciated.

Example of the input: # 20 20 30 20 # 40 50 40 60

typedef struct street
{
    int start[2];
    int end[2];
}STREET;

void main()
{
int slength=0;
STREET *streets = NULL;
...
ReadFromFile(&streets, people, buildings);
...
}

void ReadFromFile(STREET **pstreets, PERSON *people, BUILDING *buildings)
{
int slength = 0;
...
if(buffer[0] == stre)
    {
        slength += 1;
        *pstreets = (STREET*) realloc(*pstreets, (slength)*sizeof(STREET));
        fscanf(pf, "%d %d %d %d", &a,&b,&c,&d);
        *pstreets = AddStreet(&(*pstreets), slength-1,a,b,c,d);
    }
...
}

STREET* AddStreet(STREET **streets, int length, int bx, int by, int ex, int ey)
{
    if(ValidStreet(bx, by, ex, ey))
    {
        streets[length]->start[0] = bx;
        streets[length]->start[1] = by;
        streets[length]->end[0] = ex;
        streets[length]->end[1] = ey;
    }
    else
    {
        streets[length]->start[0] = ex;
        streets[length]->start[1] = ey;
        streets[length]->end[0] = bx;
        streets[length]->end[1] = by;
    }

return *streets;
}

Upvotes: 3

Views: 142

Answers (1)

WhozCraig
WhozCraig

Reputation: 66194

Your dereference logic for AddStreet is wrong. You're dereferencing length from a pointer to pointer base. You want to dereference from the pointer it points to to get the actual street object.

When streets is STREET**, then this:

streets[length]->start[0]

says "get me the pointer in the array of pointers starting at streets at offset length, then dereference that pointer". But your array isn't an array of pointers. In fact, there is only one pointer (and you happen to pass it by address).

This will do what you want:

STREET* AddStreet(STREET **streets, int length, int bx, int by, int ex, int ey)
{
    if(ValidStreet(bx, by, ex, ey))
    {
        (*streets)[length].start[0] = bx;
        (*streets)[length].start[1] = by;
        (*streets)[length].end[0] = ex;
        (*streets)[length].end[1] = ey;
    }
    else
    {
        (*streets)[length].start[0] = ex;
        (*streets)[length].start[1] = ey;
        (*streets)[length].end[0] = bx;
        (*streets)[length].end[1] = by;
    }

    return *streets;
}

Frankly, you shouldn't be passing the pointer to pointer in the first place.

void AddStreet(STREET* street, int bx, int by, int ex, int ey)
{
    if(ValidStreet(bx, by, ex, ey))
    {
        street->start[0] = bx;
        street->start[1] = by;
        street->end[0] = ex;
        street->end[1] = ey;
    }
    else
    {
        street->start[0] = ex;
        street->start[1] = ey;
        street->end[0] = bx;
        street->end[1] = by;
    }
}

invoked as this:

    fscanf(pf, "%d %d %d %d", &a,&b,&c,&d);
    AddStreet(*pstreets + (slength-1), a,b,c,d);

would work and is considerably less prone to error.

Upvotes: 3

Related Questions