Search code examples
cpointersmallocfree

"free(): invalid pointer" error when trying to free struct field of type char*


I'm trying to malloc() and then free() memory for the two char* fields in carinfo_t struct instance, but I'm getting an "invalid pointer" error on the following lines in main():

free(carToRemove->brand);
free(carToRemove->model);

and in freeCarinfo():

free(carinfo->brand);
free(carinfo->model);

Why? I'm a total newbie with C, and I've been researching for a day but I can't understand what's wrong.

Here is my code:

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

typedef struct carinfo_t
{
    char *brand;
    char *model;
    int year;
    float value;
    struct carinfo_t * next;
} carinfo_t;

struct carinfo_t *createCarinfo(char *brand, char *model, int year, float value);
struct carinfo_t *addCarinfo(struct carinfo_t *carbase, struct carinfo_t *carinfo);
struct carinfo_t *removeCarinfo(struct carinfo_t *carbase, struct carinfo_t *carinfo);
void freeCarinfo(struct carinfo_t *carinfo);


void main()
{

    struct carinfo_t *db = NULL;
    int quit = 0;
    char op;
    char *brand = malloc(25 * sizeof(char));
    char *model = malloc(25 * sizeof(char));
    int year;
    float value;

    struct carinfo_t *car1 = createCarinfo("car1", "model1", 1, 10);
    struct carinfo_t *car2 = createCarinfo("car2", "model2", 2, 80000.00);

    db = addCarinfo(db,car1);
    db = addCarinfo(db,car2);

    while (quit == 0)
    {
        printf("Command (q/r): ");
        scanf(" %c", &op);

        switch (op)
        {
            case 'q':
                quit = 1;
                break;

            case 'r':
                printf(" brand: ");
                scanf(" %[^\n]", brand);
                printf(" model: ");
                scanf(" %[^\n]", model);
                printf(" year: ");
                scanf("%d", &year);

                carinfo_t *carToRemove = createCarinfo(brand, model, year, 0);

                db = removeCarinfo(db, carToRemove);
                free(carToRemove->brand);
                free(carToRemove->model);
                free(carToRemove);
                carToRemove = NULL;
                break;

            default:
                break;
        }
    }

    free(brand);
    free(model);

}

struct carinfo_t *createCarinfo(char *brand, char *model, int year, float value)
{
    carinfo_t *newInfo = (carinfo_t *) malloc (sizeof(newInfo));

    newInfo->brand = malloc (strlen(brand) + 1);
    newInfo->model = malloc (strlen(model) + 1);

    strcpy(newInfo->brand, brand);
    strcpy(newInfo->model, model);
    newInfo->year = year;
    newInfo->value = value;
    newInfo->next = NULL;

    return newInfo;
}

struct carinfo_t *addCarinfo(struct carinfo_t *carbase, struct carinfo_t *carinfo)
{
    carinfo->next = carbase;
    return carinfo;
}

void freeCarinfo(struct carinfo_t *carinfo) 
{
    free(carinfo->brand);
    free(carinfo->model);
    free(carinfo);
}

struct carinfo_t *removeCarinfo(struct carinfo_t *carbase, struct carinfo_t *carinfo)
{
    struct carinfo_t *prev = NULL;
    struct carinfo_t *curr = carbase;

    while(curr != NULL)
    {
        if ( (strcmp(curr->brand,carinfo->brand) == 0) && (strcmp(curr->model,carinfo->model) == 0) && (curr->year == carinfo->year))
        {          
            if (prev == NULL)
            {
                carbase= curr->next;
                prev = curr;
                curr = curr->next;
                freeCarinfo(prev);
            }
            else
            {
                prev->next = curr->next;
                prev = curr;
                curr = curr->next;
                freeCarinfo(prev);
            }
        }
        else
        {
            prev = curr;
            curr = curr->next;
        }
    }

    return carbase;
}

Solution

  • the reason why you get a runtime error (invalid point) is in your createCarInfo() function. Your code is:

    struct carinfo_t *createCarinfo(char *brand, char *model, int year, float value)
    {
        carinfo_t *newInfo = (carinfo_t *) malloc (sizeof(newInfo));
        //  ... rest of your code
    

    Here, you ask malloc() to allocate N bytes. N in our case is the size of your newInfo variable. However, newInfo is a pointer to a carinfo_t structure. What you probably meant to do is allocate a carinfo_t structure on the free-store and assign its address to your newInfo pointer.

    So the correct code should be:

    struct carinfo_t *createCarinfo(char *brand, char *model, int year, float value)
        {
            carinfo_t *newInfo = malloc(sizeof *newInfo);
            //  ... rest of your code
    

    I compiled your program on my PC and tried to remove a car from your database and did not get the runtime error.

    Since you are new to C I highly recommend that you compile your source code with the Wall option (enables all compiler warnings). This will help you in the long run of learning and understanding C.