Not sure how to include functions from multiple C files [duplicate] - c

This question already has an answer here:
How to split a C program into multiple files?
(1 answer)
Closed 28 days ago.
I am not sure what is the best practice for including multiple c files. I was given two header files for an assignment, and am now required to create the corresponding c files.
Right now my issue is that I need to use functions defined in course.c in student.c, however, I am running into a linker issue that I am not sure how to resolve. The way I am currently including files is by creating multiple function definitions!
student.h
#include <stdbool.h>
#include <stdint.h>
struct course;
struct student;
struct student_id {
uint16_t sid_year;
uint32_t sid_serial;
};
struct student* student_create(struct student_id, bool grad_student);
void student_free(struct student*);
void student_take(struct student *s, struct course*, uint8_t grade);
int student_grade(struct student*, struct course*);
double student_passed_average(const struct student*);
bool student_promotable(const struct student*);
student.c
#include "student.h"
#include "course.c"
struct student
{
<Fields>
};
struct student* student_create(struct student_id id, bool grad_student)
{
<definition>
}
void student_free(struct student* s)
{
<definition>
}
void student_take(struct student *s, struct course* c, uint8_t grade)
{
<definition>
}
int student_grade(struct student* s, struct course* c)
{
<definition>
}
double student_passed_average(const struct student* s)
{
<definition>
}
bool student_promotable(const struct student* s)
{
<definition>
}
course.h
#include <stdint.h>
/** Course subjects. */
enum subject {
SUBJ_ENGI,
SUBJ_CIV,
SUBJ_ECE,
SUBJ_MECH,
SUBJ_ONAE,
SUBJ_PROC,
SUBJ_CHEM,
SUBJ_ENGL,
SUBJ_MATH,
SUBJ_PHYS,
};
struct course;
struct course* course_create(enum subject, uint16_t code);
enum subject course_subject(const struct course*);
uint16_t course_code(const struct course*);
void course_hold(struct course*);
void course_release(struct course*);
int course_refcount(const struct course*);
course.c
#include "course.h"
#include <stdio.h>
#include <stdlib.h>
struct course {
<fields>
};
struct course* course_create(enum subject sub, uint16_t code)
{
<definition>
}
enum subject course_subject(const struct course* c)
{
<definition>
}
uint16_t course_code(const struct course* c)
{
<definition>
}
void course_hold(struct course* c)
{
<definition>
}
void course_release(struct course* c)
{
<definition>
}
int course_refcount(const struct course* c)
{
<definition>
}
Which gives the following errors:
gcc *
multiple definition of `course_create'; ... first defined here ...
multiple definition of `course_subject'; ... first defined here ...
multiple definition of `course_code'; ... first defined here ...
multiple definition of `course_hold'; ... first defined here ...
multiple definition of `course_release'; ... first defined here ...
multiple definition of `ref_count'; ... first defined here ...
I am assuming this is an issue with me including course.c in student.c, but I need to include course.c to get the course structure definition. So I am wondering how I can go about retrieving the definition of struct course without using the line #include course.c

Do not #include source files. Move the structure definitions from the source files to the appropriate header files. Use include guards to avoid header files being processed more than once.
Below is a complete example that will compile cleanly with
gcc course.c student.c main.c
This is essentially an application of the answer to How to split a C program into multiple files?, but with functions and structures.
course.h:
#ifndef COURSE_H
#define COURSE_H
#include <stdint.h>
enum subject {
SUBJ_ENGI,
SUBJ_CIV,
SUBJ_ECE,
SUBJ_MECH,
SUBJ_ONAE,
SUBJ_PROC,
SUBJ_CHEM,
SUBJ_ENGL,
SUBJ_MATH,
SUBJ_PHYS,
};
struct course {
enum subject subject;
};
struct course *course_create(enum subject, uint16_t);
enum subject course_subject(const struct course *);
uint16_t course_code(const struct course *);
void course_hold(struct course *);
void course_release(struct course *);
int course_refcount(const struct course *);
#endif
student.h:
#ifndef STUDENT_H
#define STUDENT_H
#include <stdbool.h>
#include <stdint.h>
#include "course.h"
struct student {
char name[128];
};
struct student_id {
uint16_t sid_year;
uint32_t sid_serial;
};
struct student *student_create(struct student_id, bool);
void student_free(struct student *);
void student_take(struct student *, struct course *, uint8_t);
int student_grade(struct student *, struct course *);
double student_passed_average(const struct student *);
bool student_promotable(const struct student *);
#endif
course.c:
#include <stddef.h>
#include <stdint.h>
#include "course.h"
struct course *course_create(enum subject sub, uint16_t code)
{
return NULL;
}
enum subject course_subject(const struct course *c)
{
return SUBJ_ENGI;
}
uint16_t course_code(const struct course *c)
{
return 0;
}
void course_hold(struct course *c)
{
}
void course_release(struct course *c)
{
}
int course_refcount(const struct course *c)
{
return 0;
}
student.c:
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "course.h"
#include "student.h"
struct student *student_create(struct student_id id, bool grad_student)
{
return NULL;
}
void student_free(struct student *s)
{
}
void student_take(struct student *s, struct course *c, uint8_t grade)
{
}
int student_grade(struct student *s, struct course *c)
{
return 0;
}
double student_passed_average(const struct student *s)
{
return 0.0;
}
bool student_promotable(const struct student *s)
{
return false;
}
main.c:
#include <stdio.h>
#include "course.h"
#include "student.h"
int main(void)
{
struct student_id id = { 0, 0 };
struct student *stu = student_create(id, 0);
struct course *cour = course_create(SUBJ_MATH, 0);
puts("Hello world.");
}

Related

How to forward declare a typedef structure in C which has no tag

file1.h: Library code. CANT change it
#ifndef FILE1_H_
#define FILE1_H_
typedef struct
{
int x;
} MY_STRUCT;
#endif /* FILE1_H_ */
file2.h: user defined. can be changed. How to forward declare above typedef struct which has no tag ?
#ifndef FILE2_H_
#define FILE2_H_
struct MY_STRUCT;
void print(struct MY_STRUCT * obj);
#endif /* FILE2_H_ *
file2.c: user defined. can be changed
#include "file2.h"
#include "file1.h"
#include <stdio.h>
void print(struct MY_STRUCT * obj)
{
printf("x: %d", obj->x);
}
main.c
#include "file2.h"
#include "file1.h"
int main(void){
MY_STRUCT obj1;
obj1.x = 100;
print(&obj1);
}
The code can be seen here. https://paiza.io/projects/wa2PCvUswWyyAzdxxjggxQ?language=c
It's not possible to "forward-declare" a typedef . You will have to give the struct a tag, e.g.:
typedef struct my_struct MY_STRUCT;
// ... later
struct my_struct
{
int x;
};

Storage size isn't known error with structures

I'm trying to declare structures in my main() that I built in a separate file, but am getting the error:
error: storage size of 'phone' isn't known
Here is the code for main.c:
#include "header.h"
int main(int argc, char **argv)
{
struct firstAndLast name;
struct contact phone;
struct address adr;
struct allInfo individual;
print_person(individual);
return 0;
}
This is the function.c file that I wrote the structures in:
#include "header.h"
struct firstAndLast
{
char firstName[20];
char lastName[20];
};
struct contact
{
int pNumber;
};
struct address
{
struct firstAndLast person;
struct contact phoneNumber;
char streetAddress[100];
char city[50];
char province[50];
char postalCode[10];
};
struct allInfo
{
struct address addr;
char occupation[50];
double salary;
};
void print_person(struct allInfo indiv)
{
printf("%s \n",indiv.addr.person.firstName);
}
And this is the header.h file:
#ifndef nS
#define nS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct firstAndLast;
struct contact;
struct address;
struct allInfo;
void print_person(struct allInfo indiv);
#endif
I'm not sure why I am getting this error. I put all of the functions in the header file and used #include "header.h" for both my main.c and functions.c files, so it should recognize the structures exist. Is there a problem with the way that I declared the structures in main() or how I listed them in my header? I don't see any typos in my code, so I'm really lost and don't know what I'm doing wrong.
First, you need to move full struct definitions into the header file.
#pragma once
#ifndef nS
#define nS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct firstAndLast
{
char firstName[20];
char lastName[20];
};
struct contact
{
int pNumber;
};
struct address
{
struct firstAndLast person;
struct contact phoneNumber;
char streetAddress[100];
char city[50];
char province[50];
char postalCode[10];
};
struct allInfo
{
struct address addr;
char occupation[50];
double salary;
};
void print_person(struct allInfo indiv);
#endif
Moreover, please initialize each variable before using them.
For example:
struct firstAndLast name;
strcpy(name.firstName, "firstNameA");
strcpy(name.lastName, "lastNameB");
struct contact phone;
phone.pNumber = 01234567;
struct address adr;
adr.person = name;
adr.phoneNumber = phone;
strcpy(adr.streetAddress, "ABC street");
strcpy(adr.city, "DEF city");
strcpy(adr.province, "GH");
strcpy(adr.postalCode, "12345");
struct allInfo individual;
individual.addr = adr;
strcpy(individual.occupation, "Occupation");
individual.salary = 1234.56;
print_person(individual);

How can I resolve this mutual dependency between header files?

Please note, there are several questions regarding circular dependencies on SO (including one I have asked myself), but I feel none of them has helped me with this particular problem.
Please consider the two following files:
table.h
#ifndef s_table_h
#define s_table_h
#include "value.h"
#include "object.h"
typedef struct {
ObjectString* key;
Value value;
} Entry;
typedef struct {
int capacity;
int count;
Entry* entries;
} Table;
void initTable(Table* table);
void setTable(Table* table, ObjectString* key, Value value);
bool getTable(Table* table, ObjectString* key, Value* out);
#endif
object.h
#ifndef s_object_h
#define s_object_h
#include "common.h"
#include "table.h"
typedef enum {
OBJECT_STRING
} ObjectType;
typedef struct {
ObjectType type;
Table attributes;
} Object;
typedef struct {
Object base;
char* chars;
int length;
} ObjectString;
bool stringsEqual(ObjectString* a, ObjectString* b);
#endif
As you can see, these two depend on each other: table.h needs ObjectString*, and object.h needs a concrete Table. Both corresponding .c implementation files access concrete members of the ObjectString* and Table respectively.
What is the recommended way to solve this problem? And generally, what would be the common approach to these kinds of problems in C?
Please address purely the technical aspect, and not the software-design one.
I suppose you could argue that I'm addressing the software-design aspect here, but I don't know how to do this without slightly refactoring your code. Namely, by avoiding the typedef temporarily. (Although I would advise dumping the typedef's permanently.) For your particular case, table.h doesn't need to know what ObjectString is, since it only uses a pointer to it. So you can simply not import "object.h" in table.h, and instead write:
object.h:
#ifndef s_object_h
#define s_object_h
#include "common.h"
#include "table.h"
typedef enum {
OBJECT_STRING
} ObjectType;
typedef struct {
ObjectType type;
Table attributes;
} Object;
struct ObjectString {
Object base;
char* chars;
int length;
};
typedef struct ObjectString ObjectString;
bool stringsEqual(ObjectString* a, ObjectString* b);
#endif
table.h:
#ifndef s_table_h
#define s_table_h
#include "value.h"
typedef struct {
struct ObjectString* key;
Value value;
} Entry;
typedef struct {
int capacity;
int count;
Entry* entries;
} Table;
void initTable(Table* table);
void setTable(Table* table, struct ObjectString* key, Value value);
bool getTable(Table* table, struct ObjectString* key, Value* out);
#endif
Maybe you can do like this,put table.h and object.h together to one file named both.h,no longer need table.h and object.h,only use both.h:
#ifndef s_table_h
#define s_table_h
#include "value.h"
#include "common.h"
//#include "object.h"
//#include "table.h"
typedef struct A ObjectString; // add
typedef struct {
ObjectString* key;
Value value;
} Entry;
typedef struct {
int capacity;
int count;
Entry* entries;
} Table;
typedef enum {
OBJECT_STRING
} ObjectType;
typedef struct {
ObjectType type;
Table attributes;
} Object;
typedef struct A { // modify to typedef struct A
Object base;
char* chars;
int length;
} ObjectString;
bool stringsEqual(ObjectString* a, ObjectString* b);
void initTable(Table* table);
void setTable(Table* table, ObjectString* key, Value value);
bool getTable(Table* table, ObjectString* key, Value* out);
#endif

Memory allocation error in C during hashing

I am new to C programming and I was trying to implement typedef and hashing in my code.But I am getting compilation error when I try to allocate memory -
This is my header file
#define MAX1 11
#define MAX2 23
typedef short IP[4];
typedef enum{TRUE = 1,FALSE = 0}boolean;
typedef struct
{
IP p;
char *comp_name;
}Element;
typedef struct
{
Element e;
boolean deleted; // deleted flag
boolean empty;
}Cell;
typedef Cell secLevelHashTable[MAX2];
typedef struct secLevelHashTable *FirstLevelHashTable[MAX1];
typedef struct FirstLevelHashTable hashTable;
This my main code-
#include"hashDef.h"
#include<stdio.h>
#include<stdlib.h>
void initFirstHTable(hashTable H)
{
int i,j;
for(i=0;i<MAX1;i++)
{
H. FirstLevelHashTable[i]=(secLevelHashTable *)malloc(sizeof(secLevelHashTable));
H.FirstLevelHashTable[i]->secLevelHashTable=malloc(sizeof(Cell)*MAX2);
for(j=0;j<MAX2;j++)
{
initSecHTables(H.FirstLevelHashTable[i]->secLevelHashTable[j]);
}
}
}
void initSecHTables(Cell *ptr)
{
ptr->deleted=0;
ptr->empty=1;
}
int main()
{
hashTable h;
h=malloc(sizeof(FirstLevelHashTable));
initFirstHTable(h);
return 0;
}
This is the error I am getting-
In function ‘main’:
hashOps.c:79:13: error: storage size of ‘h’ isn’t known
hashTable h;
Fixed code below. It had numerous small issues and a big one.
Please read the related article the big one:
struct in C: Error storage size of 'params' isn't known -- this will explain "storage size unknown" error; by saying typedef struct FirstLevelHashTable hashTable; you were defining an unfinished struct, rather than referring to existing type.
Header file:
#define MAX1 11
#define MAX2 23
typedef short IP[4];
typedef enum{TRUE = 1,FALSE = 0}boolean;
typedef struct
{
IP p;
char *comp_name;
}Element;
typedef struct
{
Element e;
boolean deleted; // deleted flag
boolean empty;
}Cell;
typedef Cell secLevelHashTable[MAX2];
typedef secLevelHashTable* FirstLevelHashTable[MAX1];
typedef FirstLevelHashTable hashTable;
Main code:
#include"hashDef.h"
#include <stdio.h>
#include <stdlib.h>
void initSecHTables(Cell *ptr)
{
ptr->deleted=0;
ptr->empty=1;
}
void initFirstHTable(hashTable H)
{
int i,j;
for(i=0;i<MAX1;i++)
{
H[i]=(secLevelHashTable *)malloc(sizeof(secLevelHashTable));
for(j=0;j<MAX2;j++)
{
initSecHTables(&((*H[i])[j]));
}
}
}
int main()
{
hashTable h;
initFirstHTable(h);
return 0;
}

Conflicting types for 'Graph' error

I'm getting an error saying 'conflicting types for 'Graph' for the following code, but I'm not sure what the issue is, as Graph is declared before it is used anywhere. Anyone know what the issue is?
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#define __USE_BSD // make prototype for strdup visible
#include <string.h>
typedef struct linkedlist { // linked list of ints (for use in Node)
int index;
struct linkedlist *next;
} List;
typedef struct { // a Node of a Graph
char *name;
List *outlist; // adjacency list
int outdegree; // length of outlist
int indegree; // length of inlist
int dfsnum;
//double pagerank_score; //not needed for this exercise
} Node;
typedef struct {
int MaxSize;
Node *table;
} Graph;
// use to check result of strdup, malloc etc.
extern void check (void *memory, char *message);
extern int initialize_graph (Graph *mygraph, int MaxSize);
extern int insert_graph_node (Graph *mygraph, int n, char *name);
extern int insert_graph_link (Graph *mygraph, int source, int target);
extern int read_graph (Graph *mygraph, char *filename);
extern void print_graph (Graph *mygraph);
I am not sure but i think CDT MinGW has an extended C lib which already has a variable name reserved which is called "Graph", have you tried renaming your struct? This might be the case though i have never worked with CDT MinGW before

Resources