I have a working generic graph. The type for vertex is currently defined as:
typedef struct vertex {
void *data;
char *label;
bool inGraph;
} vertex;
The void pointer can then be customized for any algorithm, like BFS, DFS, etc. This works, but I want to simplify the code by using a separate header file for a vertex that specifies its type as needed, and is included in graph.h. Something like this:
#ifndef VERTEX_H_INCLUDED
#define VERTEX_H_INCLUDED
#include <stdlib.h>
#include <stdbool.h>
#if defined (GRAPH_VERTEX1)
typedef struct vertex {
struct vertex *parent;
char *label;
bool inGraph;
} vertex;
#elif defined (GRAPH_VERTEX2)
typedef struct vertex {
size_t dist;
char *label;
bool inGraph;
} vertex;
#else // default
typedef struct vertex {
char *label;
bool inGraph;
} vertex;
#endif
#endif
This does not work, however. The right vertex type is not selected and allocated.
I have made an example to reproduce the issue.
main.c
#include <stdio.h>
#define GRAPH_VERTEX1
#include "graph.h"
int main() {
vertex *v = createVertex("test");
v->inGraph = true;
vertex *parent = createVertex("parent");
printf("Vertex: %s\n", v->label);
printf("Parent: %s\n", parent->label);
printf("In graph: %d\n", parent->inGraph);
freeVertex(v);
freeVertex(parent);
return 0;
}
graph.h
#ifndef GRAPH_H_INCLUDED
#define GRAPH_H_INCLUDED
#include <stdlib.h>
#include "vertex.h"
vertex *createVertex(char *label);
void freeVertex(vertex *v);
#endif
graph.c
#include "graph.h"
#include <string.h>
vertex *createVertex(char *label) {
vertex *v = calloc(1, sizeof(vertex));
v->label = calloc(strlen(label) + 1, sizeof(char));
v->inGraph = false;
strcpy(v->label, label);
return v;
}
void freeVertex(vertex *v) {
free(v->label);
free(v);
}
The example works fine if I put a single definition in vertex.h. However, if I try to use the if directives, I get the following errors:
==986== Memcheck, a memory error detector
==986== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==986== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==986== Command: ./a.out
==986==
==986== Invalid write of size 1
==986== at 0x1090FD: main
==986== Address 0x4a8e050 is 0 bytes after a block of size 16 alloc'd
==986== at 0x484DA83: calloc
==986== by 0x109279: createVertex
==986== by 0x1090F5: main
==986==
==986== Invalid read of size 1
==986== at 0x10913A: main
==986== Address 0x4a8e0f0 is 0 bytes after a block of size 16 alloc'd
==986== at 0x484DA83: calloc
==986== by 0x109279: createVertex
==986== by 0x109108: main
==986==
Vertex: (null)
Parent: (null)
In graph: 0
==986==
==986== HEAP SUMMARY:
==986== in use at exit: 0 bytes in 0 blocks
==986== total heap usage: 5 allocs, 5 frees, 4,140 bytes allocated
==986==
==986== All heap blocks were freed -- no leaks are possible
==986==
==986== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
==986==
==986== 1 errors in context 1 of 2:
==986== Invalid read of size 1
==986== at 0x10913A: main
==986== Address 0x4a8e0f0 is 0 bytes after a block of size 16 alloc'd
==986== at 0x484DA83: calloc
==986== by 0x109279: createVertex
==986== by 0x109108: main
==986==
==986==
==986== 1 errors in context 2 of 2:
==986== Invalid write of size 1
==986== at 0x1090FD: main
==986== Address 0x4a8e050 is 0 bytes after a block of size 16 alloc'd
==986== at 0x484DA83: calloc
==986== by 0x109279: createVertex
==986== by 0x1090F5: main
==986==
==986== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
graph.c
needs to have the same #define GRAPH_VERTEX1
as you have in main.c
- otherwise that translation unit will get the default vertex
definition (since neither GRAPH_VERTEX1
nor GRAPH_VERTEX2
will be defined).
You could put #define GRAPH_VERTEX1
in a separate header file that you include from both main.c
and graph.c
:
#ifndef SOMENAME_H
#define SOMENAME_H
#define GRAPH_VERTEX1
#include "graph.h"
#endif
... or just put it at the top of graph.h
.
Alternatively, tell your compiler to define it from the command line. Example:
gcc -DGRAPH_VERTEX1 ...