0

I am facing some issues regarding a realloc with a double pointer dynamic array. What I would like to perform is to add 2 pointers of type Flight* inside the array schedule of type Flight **.

For that, I am relying on the function add_flight in the Functions.c file. This function asks the user for the airline and flight number values and stores these data in a new Flight* f. If the schedule is null (no flight yet added) it allocates memory for the newly created flight otherwise it realloc the size of schedule in order the add the new flight.

Main.c file:

int main() {
    int choice = 1;
    Flight** schedule = NULL;   

    printf("---AIRPORT MANAGER---");
    schedule = add_flight(schedule);
    printf("\n%s : %d\n", (*schedule)->airline, (*schedule)->flightNumber);
    schedule = add_flight(schedule);
    printf("\n%s : %d\n", (*schedule + 1)->airline, (*schedule)->flightNumber);

    return 0;
}

Functions.c file :

#include "Functions.h"

void mygets(char* s, int maxLength) {
    fflush(stdout);
    if (fgets(s, maxLength, stdin) != NULL) {
        size_t lastIndex = strlen(s) - 1;
        if (s[lastIndex] == '\n')
            s[lastIndex] = '\0';
    }
}

void flush() {
    char buffer;
    while ((buffer = getchar()) != EOF && buffer != '\n');
}

Flight** add_flight(Flight** schedule) {
    Flight* f;
    char buffer[100];

    if ((f = (Flight*)malloc(sizeof(Flight*))) == NULL) {
        exit(1);
    }

    printf("\n\n---FLIGHT CREATION---");
    printf("\nAirline: ");
    mygets(buffer, sizeof(buffer));
    if ((f->airline = _strdup(buffer)) == NULL) {
        exit(1);
    }
    memset(buffer, 0, 100);

    printf("\nFlight number: ");
    scanf("%d", &f->flightNumber);
    flush();

    if (schedule == NULL) {
        if ((schedule = malloc(sizeof(Flight*))) == NULL) {
            exit(1);
        }       
        *schedule = f;
    }
    else {
        int numberFlights = ((sizeof(*schedule)) / 4) + 1;
        if ((schedule = realloc(schedule, numberFlights * sizeof(Flight*))) == NULL) {
            exit(1);
        }
        *(schedule + numberFlights -1) = f;
    }

    return schedule;
}

The issue comes when the second call of add_flight is performed in the main.c

In the add_flight function, the data are indeed stored in the new Flight* f and then the else statement is considered: the variable numberFlights gets the value 2. However, the realloc doesn't work, the schedule is not enlarged and thus there is still only the first flight stored inside this schedule array. I can't figure out why the second flight is not added inside the schedule.

Can someone explain me why this realloc fails ? Thanks for your help :)

3
  • 1
    With malloc(sizeof(Flight*) you are reserving space with the size of a pointer, to use the size of the struct itself use malloc(sizeof(Flight)) or better yet: malloc(sizeof *f) Commented Apr 14, 2020 at 9:22
  • 2
    There's no way to tell how many flights there are in your dynamic array with the sizeof operator. You must keep track of the number of flights differently, for example with an extra variable or by appending a special sentinel value at the end of all flights. (The sizeof operator is evaluated at compile time here, but you want to know how many flights there are at run time, of course.) Commented Apr 14, 2020 at 9:24
  • @MOehm Thanks for your answer, I added a variable numberOfFlights which is getting incremented each time I add a flight. However, it still doesn't work, the second flight is not added Commented Apr 14, 2020 at 12:20

1 Answer 1

1

The sizeof operator is evaluated at compile time. It cannot be used to determine the size of a dynamically allocated array.

C imposes the burden of keeping track of the actual size of an array onto the programmer. You could kee a separate count variable, but because the actual array and its size belong together, it is useful to store them alongside each other in a struct:

typedef struct Flight Flight;
typedef struct Flights Flights;

struct Flight {
    char airline[4];
    int number;
    char dest[4];
};

struct Flights {
    Flight *flight;
    int count;
};

Instead of operating on the array, operate on the struct:

void add_flight(Flights *fl,
    const char *airline, int number, const char *dest)
{
    int n = fl->count++;        // n is old count; fl->count is new count

    fl->flight = realloc(fl->flight,
        (fl->count + 1) * sizeof(*fl->flight));

    snprintf(fl->flight[n].airline, 4, "%s", airline);
    snprintf(fl->flight[n].dest, 4, "%s", dest);
    fl->flight[n].number = number;
}

Intialize the flights struct with NULL and a count of zero and don't forget to release the used memory when you're done:

int main(void)
{
    Flights fl = {NULL, 0};

    add_flight(&fl, "AF", 5512, "CDG");
    add_flight(&fl, "AA", 1100, "ATL");
    add_flight(&fl, "LH", 6537, "FRA");
    add_flight(&fl, "BA", 8821, "LHR");
    add_flight(&fl, "IB", 1081, "EZE");

    print_flights(&fl);

    free(fl.flight);

    return 0;
}

You can see it in action here. Some observations:

  • There is no need to distinguish between adding the first and subsequent flights, because realloc(NULL, size) behaves exactly like malloc(size).
  • It is not very efficient to reallocate the memory for each added item. Instead, you pick a suitable initial array size like 4 or 8, then double the size when you hit the limit. That means that the allocated size and the count may differ and you need an aditional memsize field in your flights struct.
  • The code above relies on manual initialization and destruction. Usually, you will write "constructor" and "destructor" functions to do that for you.
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot for your explanation and your help @MOehm ! Everything is now working :)
In my instructions, I have to use a double-pointer in order to use as less memory as possible. Therefore I modify a little your code: the struct flight has now pointers to char variables instead of char. And the flights structure has now the variable Flight** flight instead of Flight* flight. However, in the function add_flight I don't manage to store the value since the flight is type double pointer. I have tried this: fl->flight[n]->airline = _strdup(airline) but it doesn't work. Do you have any idea to make this working?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.