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

95 Views Asked by At

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

2

There are 2 best solutions below

2
Eric Postpischil On BEST ANSWER

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.)

6
Vlad from Moscow On

In this structure declaration

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

there is used a pointer of the type point * where the type point is incomplete because within the module polygon.c there is no definition of the structure Point that has the typedef name point.

So compiling the function

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

the compiler does not know whether point (the structure Point) indeed has data members x and y.

As a result the error message is issued by the compiler.

You need also to include the definition of the structure Point in this module.