I have point.h and polygon.h files, with their associated .c files. In point.h
// point.h
#ifndef POINT_H
#define POINT_H
typedef struct Point point;
point *point_alloc(void);
void *point_free(point *);
void *point_init(point *, float, float);
void *point_print(const point *);
float point_get_x(const point *);
float point_get_y(const point *);
void *point_set_x(point *, float);
void *point_set_y(point *, float);
#endif
In point.c, I have
// point.c
#include <stdlib.h>
#include <stdio.h>
#include "point.h"
#define GET_VALUE_ERROR (2L)
struct Point
{
float x;
float y;
};
point *point_alloc(void)
{
point *pt = malloc(sizeof *pt);
if(NULL == pt)
{
fprintf(stderr, "Could not allocate point.\n");
return NULL;
}
else
{
return pt;
}
}
void *point_free(point *pt)
{
if(NULL == pt)
{
fprintf(stderr, "Could not free point.\n");
return NULL;
}
else
{
free(pt);
pt = NULL;
return NULL;
}
}
void *point_init(point *pt, float x, float y)
{
if(NULL == pt)
{
fprintf(stderr, "Cannot initiate point.\n");
return NULL;
}
else
{
pt -> x = x;
pt -> y = y;
return NULL;
}
}
void *point_print(const point *pt)
{
if(NULL == pt)
{
fprintf(stderr, "Cannot print point.\n");
return NULL;
}
else
{
printf("Point at (%f, %f)\n", pt -> x, pt -> y);
return NULL;
}
}
float point_get_x(const point *pt)
{
if(NULL == pt)
{
fprintf(stderr, "Cannot get point.\n");
return GET_VALUE_ERROR;
}
else
{
return pt -> x;
}
}
float point_get_y(const point *pt)
{
if(NULL == pt)
{
fprintf(stderr, "Cannot get point.\n");
return GET_VALUE_ERROR;
}
else
{
return pt -> y;
}
}
void *point_set_x(point *pt, float x)
{
if(NULL == pt)
{
fprintf(stderr, "Cannot get point.\n");
return NULL;
}
else
{
pt -> x = x;
return NULL;
}
}
void *point_set_y(point *pt, float y)
{
if(NULL == pt)
{
fprintf(stderr, "Cannot get point.\n");
return NULL;
}
else
{
pt -> y = y;
return NULL;
}
}
while in polygon.h I have
// polygon.h
#ifndef POLYGON_H
#define POLYGON_H
typedef struct Polygon polygon;
polygon *polygon_alloc(unsigned);
void *polygon_free(polygon *);
void *polygon_init(polygon *, unsigned, float, point *);
void *polygon_print(const polygon *);
unsigned polygon_get_nside(const polygon *);
void *polygon_set_nside(polygon *, unsigned);
point *polygon_get_centre(const polygon *);
void *polygon_set_centre(polygon *, point *);
point *polygon_get_vertex(const polygon *, unsigned);
void *polygon_set_vertex(polygon *, unsigned, float, float);
#endif
and in polygon.c I have
// polygon.c
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "point.h"
#include "polygon.h"
#ifndef M_PI
#define M_PI (3.14159265358979323846264338327950288)
#endif
#define GET_NSIDE_ERROR (2U)
struct Polygon
{
unsigned nside;
point *centre;
point **vertices;
};
polygon *polygon_alloc(unsigned nside)
{
if(nside == 0)
{
fprintf(stderr, "Cannot have a 0-sided polygon.\n");
return NULL;
}
else
{
polygon *poly = malloc(sizeof(*poly));
if(NULL == poly)
{
fprintf(stderr, "Cannot allocate polygon.\n");
return NULL;
}
else
{
poly -> nside = nside;
poly -> centre = point_alloc();
if(NULL == poly -> centre)
{
fprintf(stderr, "Cannot allocate polygon centre.\n");
free(poly);
poly = NULL;
return NULL;
}
else
{
poly -> vertices = malloc(nside * sizeof(point*));
if(NULL == poly -> vertices)
{
fprintf(stderr, "Cannot allocate polygon vertices.\n");
free(poly -> centre);
poly -> centre = NULL;
free(poly);
poly = NULL;
return NULL;
}
else
{
for(unsigned i = 0; i < nside; i++)
{
poly -> vertices[i] = point_alloc();
if(NULL == poly -> vertices[i])
{
fprintf(stderr, "Cannot allocate node %u.\n", i);
for(unsigned j = 0; j < i; j++)
{
free(poly -> vertices[j]);
poly -> vertices[j] = NULL;
}
free(poly -> centre);
poly -> centre = NULL;
free(poly -> vertices);
poly -> vertices = NULL;
free(poly);
poly = NULL;
}
}
}
}
}
return poly;
}
}
void *polygon_free(polygon *poly)
{
if(NULL == poly)
{
fprintf(stderr, "Cannot free polygon.\n");
return NULL;
}
else
{
if(NULL == poly -> centre)
{
fprintf(stderr, "Cannot free polygon centre.\n");
return NULL;
}
else
{
free(poly -> centre);
poly -> centre = NULL;
if(NULL == poly -> vertices)
{
fprintf(stderr, "Cannot free polygon vertices.\n");
return NULL;
}
else
{
for(unsigned i = 0; i < poly -> nside; i++)
{
if(NULL == poly -> vertices[i])
{
fprintf(stderr, "Cannot free vertex %u.\n", i);
return NULL;
}
else
{
free(poly -> vertices[i]);
poly -> vertices[i] = NULL;
}
}
free(poly -> vertices);
poly -> vertices = NULL;
}
}
free(poly);
poly = NULL;
}
return NULL;
}
void *polygon_init(polygon *poly, unsigned nside, float radius, point *centre)
{
if(NULL == poly)
{
fprintf(stderr, "Polygon not existing.\n");
return NULL;
}
else if(NULL == centre)
{
fprintf(stderr, "Polygon centre not existing.\n");
return NULL;
}
else
{
polygon_set_nside(poly, nside);
polygon_set_centre(poly, centre);
for(unsigned i = 0; i < poly -> nside; i++)
{
float angle = (1 + 2 * i) * (M_PI / poly -> nside);
float x = radius * cos(angle);
float y = radius * sin(angle);
polygon_set_vertex(poly, i, x, y);
}
return NULL;
}
}
void *polygon_set_nside(polygon *poly, unsigned nside)
{
if(NULL == poly)
{
fprintf(stderr, "Cannot set polygon number of sides.\n");
return NULL;
}
else
{
poly -> nside = nside;
return NULL;
}
}
void *polygon_set_centre(polygon *poly, point *centre)
{
if(NULL == poly)
{
fprintf(stderr, "Cannot set polygon number of sides.\n");
return NULL;
}
else
{
poly -> centre = centre;
return NULL;
}
}
// Rest of implementation
Apparently, the allocation and/or free of the polygon is not correct. To see this, I wrote this main.c reading
#include <stdio.h>
#include <stdlib.h>
#include "point.h"
#include "polygon.h"
int main() {
unsigned nside = 3;
float radius = 1.0;
point* centre = point_alloc();
point_init(centre, 0.0, 0.0);
polygon* poly = polygon_alloc(nside);
polygon_init(poly, nside, radius, centre); // this one is a problem
polygon_print(poly);
polygon_free(poly);
point_free(centre);
exit(EXIT_SUCCESS);
}
compiled using the command gcc -Wall -Wextra -Wpedantic -Werror -std=c99 .\point.c .\polygon.c .\main.c -o .\main.exe, I have a a "red cross in my IDE (I use VSCode), as illustrated here in the picture (which indicates that something is wrong) and I do not know neither from where it comes, nor how to solve it?

EDIT
I corrected the allocation/freeing function thanks to the answer below, and was able to find that the problem is caused by the polygon_init function, but I cannot pinpoint what is wrong there?
Your program segfaults in
free_polygon()because you free theverticesarray before each of itsverticies[i]element:In general you want to free resources in reverse order of how they are allocated (free
vertices[i]beforevertices). Any error infree_polygon()may result in memory leaks. For example ifpoly->vertices[i] == NULLthen we don't free remainingpoly->verticies[i],poly->vertices,poly->centreorpoly. As youralloc_polygon()takes care of partial constructions is probably ok but it's a risky design:Other suggestions:
free_polygon()always returnNULLconsider changing it's return type tovoid.!polyis easier to read thenNULL == poly.alloc_polygon()is quite complicated; consider designing the allocation and free function as a matching pair so you can always callfree_polygon()on a partially constructed object by initializing variables with NULL,callocinstead ofmalloc()ofverticiesand free resources in reverse. I routinely usegotofor cleanup chains but if you have qualms you can duplicate those two lines instead in each error case. Compilers (at least gcc) will warn you if you miss a variable initialization before agotowhich I find helpful.polyobject's lifetime expired after a call tofree_polygon()I never bother setting any of the variables toNULL. That said it may help you catch a use after free defect.polygon_alloc()instead ofalloc_polygon().polygon *polytopolygon* poly. It avoids confusion if you ever declare two pointers on one line.