Giedrius
Giedrius

Reputation: 1390

C - dynamic array in a struct - crash after reallocation

I am new to C and trying to have a dynamic array inside a struct, to which I need to add a dynamic number of items.

If I use malloc with a big number (like +100000) when initialising the container, the program works fine.

However, if I just allocate sizeof(struct ...) memory, and then try to reallocate using realloc, the program crashes when I try to add new item to the array. Even if I add +1000000 size when reallocating, it still crashes, while the same size works if I use it when allocating in the first place.

Cut down code to display my problem:

struct Station {
    char name[100];
};

struct StationContainer {
    int numberOfStations;
    struct Station *stations[];
};

struct StationContainer *makeContainer() {
    struct StationContainer *new;
    // If I add +1000000 in size here, the program works fine
    new = (struct StationContainer *) malloc(sizeof(struct StationContainer));

    if (new == NULL) {
        fprintf(stderr, "makeContainer: out of memory\n");
        exit(1);
    }

    new->numberOfStations = 0;

    return new;
}

int main(int argc, int argv[]) {

    // Initialize the container
    struct StationContainer *container;
    container = makeContainer();

    // Add new station to container
    struct Station *new;
    new = (struct Station *) malloc(sizeof(struct Station));

    if (new == NULL) {
        fprintf(stderr, "makeStation: out of memory\n");
        exit(1);
    }

    strcpy(new->name, name);

    // Add to the container
    // Even if I add +1000000 here, it still crashes below when I add new item
    container = (struct StationContainer *) realloc(container, sizeof(struct StationContainer) + 1000000);

    if (container == NULL) {
        fprintf(stderr, "makeStation: container out of memory\n");
        exit(1);
    }

    container->stations[container->numberOfStations] = new;
    container->numberOfStations++;


}

EDIT1: The problem in my cut down version was spotted, however, once I returned to full version, I was still getting the error. I got the container out of memory. That was because my container->numberOfStations was wildly big after first increment for some reason.

My full code at: codepad

The adjacencies.txt file contents:

Baker Street, Bond Street, Regent's Park
Bond Street, Marble Arch, Baker Street, Oxford Circus, Green Park
Marble Arch, Bond Street
Green Park, Bond Street, Oxford Circus, Piccadilly Circus
Regent's Park, Baker Street, Oxford Circus
Oxford Circus, Bond Street, Regent's Park, Warren Street, Tottenham Court Road, Piccadilly Circus
Piccadilly Circus, Green Park, Oxford Circus, Leicester Square, Charing Cross
Warren Street, Oxford Circus, Goodge Street
Goodge Street, Warren Street, Tottenham Court Road
Tottenham Court Road, Oxford Circus, Goodge Street, Holborn, Leicester Square
Leicester Square, Piccadilly Circus, Tottenham Court Road, Covent Garden, Charing Cross
Charing Cross, Piccadilly Circus, Leicester Square
Covent Garden, Leicester Square, Holborn
Holborn, Tottenham Court Road, Chancery Lane
Chancery Lane, Holborn

When I make the stations, if I leave container->numberOfStations unchanged, there is no problem. However, when I at least increment it once, combined with the realloc, it changes to huge numbers. Example output:

Number of stations: 0
!Station name:[Baker Street]
Number of stations: 1
!Station name:[Bond Street]
Number of stations: 4067560
makeStation: container out of memory

I feel like there is a small error somewhere that makes my numberOfStation change wildly even though it's supposed to increment just by one?

Upvotes: 0

Views: 156

Answers (2)

Daniel Bungert
Daniel Bungert

Reputation: 163

In the original version posted, container->numberOfStations was uninitialized.
In makeContainer you might consider using calloc() or memset() to initialize your container to zero - it works nicely when you add new items to the struct and they still should be initialized to zero.

In the current version I can spot no error, and neither can valgrind. I took the liberty of declaring a name within the constraints of the 100 char limit.

Upvotes: 4

Ed Heal
Ed Heal

Reputation: 59997

Well - look at

struct StationContainer {
    int numberOfStations;
    struct Station *stations[];
};

So stations is pointer

So makeContainer just gives it enough space for a pointer etc. You have not even allocated the memory for the pointer to have information nor initialised numberOfStations. It is just an uninitialised pointer

PS: Does this compile

   strcpy(new->name, name);

Cannot find the declaration for name

Upvotes: 2

Related Questions