cpointersstructincomplete-type

Why do I get an incomplete type in my C code?


I have two header files, namely point.h and polygon.h

//point.h
#ifndef POINT_H
#define POINT_H

typedef struct Point point;

point *alloc_point(void);
int free_point(point *);
void init_point(point *, float, float);
void print_point(point *);

#endif

and

//polygon.h
#ifndef POLYGON_H
#define POLYGON_H

typedef struct Polygon polygon;

polygon *alloc_polygon(void);
int free_polygon(polygon *);
void init_polygon(polygon *, unsigned, point *);
void print_polygon(polygon *);

#endif

with the corresponding point.c and polygon.c files

//point.c
#include <stdlib.h>
#include <stdio.h>
#include "point.h"

struct Point
{
    float x;
    float y;
};

point *alloc_point(void)
{
    point *pt = (point *)malloc(sizeof(point));

    if (pt)
    {
        return pt;
    }
    else
    {
        fprintf(stderr, "Could not allocate point. Aborting\n");
        exit(EXIT_FAILURE);
    }
}

int free_point(point *pt)
{
    if (pt)
    {
        free(pt);
        pt = NULL;
        return 1;
    }
    else
    {
        fprintf(stderr, "Could not free point. Aborting\n");
        return 0;
    }
}

void init_point(point *pt, float x, float y)
{
    pt->x = x;
    pt->y = y;
}

void print_point(point *pt)
{
    printf("Point at (%f, %f)\n", pt->x, pt->y);
}

and

//polygon.c
#include <stdio.h>
#include <stdlib.h>
#include "point.h"
#include "polygon.h"

struct Polygon
{
    unsigned nside;
    point *centre;
};

polygon *alloc_polygon(void)
{
    polygon *poly = (polygon *)malloc(sizeof(polygon));

    if (poly)
    {
        return poly;
    }
    else
    {
        fprintf(stderr, "Cannot allocate polygon. Aborting\n");
        exit(EXIT_FAILURE);
    }
}

int free_polygon(polygon *poly)
{
    if (poly)
    {
        free(poly);
        poly = NULL;
        return 1;
    }
    else
    {
        fprintf(stderr, "Cannot free polygon. Aborting\n");
        exit(EXIT_FAILURE);
    }
}

void init_polygon(polygon *poly, unsigned nside, point *centre)
{
    poly->nside = nside;
    poly->centre = centre;
}

void print_polygon(polygon *poly)
{
    printf("%u-sided polygon with centre at (%f, %f)",
           poly->nside, poly->centre->x, poly->centre->y);
}

When I try to run main.c, which contains

#include <stdio.h>
#include "point.h"
#include "polygon.h"

int main() {
    point *centre = alloc_point();
    init_point(centre, 10.0, 10.0);
    print_point(centre);

    unsigned nside = 4;
    polygon *poly = alloc_polygon();
    init_polygon(poly, nside, centre);
    print_polygon(poly);

    free_point(centre);
    free_polygon(poly);
    return 0;
}

I get the error message (coming from the print_polygon method inside polygon.c)

error: dereferencing pointer to incomplete type 'point' {aka 'struct Point'}

I do not get that error as the definition of the Polygon structure has a pointer to point. Why can I not get the code running?

P.S.: I use gcc 8.1.0 and compile using gcc -Os -Wall -Wextra -Wpedantic -Werror -std=c99 .\main.c .\point.c .\polygon.c -o .\main.exe


Solution

  • In poly -> centre -> x, poly -> centre is a pointer to a point, and -> x dereferences that point, but polygon.c does not have a complete definition of point. It only knows point is struct Point but not what the contents of struct Point are.

    Some options to fix this are:

    1. Define a routine in point.c that will print the point’s coordinates, export that routine from point.c (via point.h), and call it from print_polygon.
    2. Define a routine or routines in point.c that will provide the coordinates, export that routine or routines, and call it or them from print_polygon to get the values to print.
    3. Make the definition of struct Point visible in polygon.

    The first is best for preserving modularity.

    (In 2, the coordinates could be provided by returning them from one routine in a structure whose definition is shared between point.c and polygon.c, by returning the two float coordinates in separate routines, one for each, or by returning the two float coordinates in float objects passed by reference.)