Reputation: 21
I have a problem with my code. I have programmed a pharmacy management system (2000 loc). Now I want to outsource several functions (Supplier(6 functions), Customer(6 functions) and Medizine(9 functions)) into 3 c Files.
The code works perfectly fine in one C function but somehow it gives me errors when putting it into different .c Files. It seems like it has to do something with my header file which is included in every .c File. Because it says that there are multiple declarations of stuff from the header.(It worked when only having 1 .c File).
These are the errors when compiling:
.
This is my header File:
#ifndef MAINPROJECTNIKLASLOREK_H_
#define MAINPROJECTNIKLASLOREK_H_
//Anlegen eines const char pointer um das Format des Medizinstructs festzulegen und später
bei printf Ausgaben direkt anzuwenden
const char* medicine_format ="\n\tMediID:%s\n\tMediName:%s\n\tQuantity:%d\n\tPrice:%.2f
\n\tExp.Date:%s\n\tCompany:%s\n\tSupplier:%s\n\tInfo:%s\n";
//Anlegen eines Structs für die Medizin
struct Medicine{
int quantity;
float price;
char expdate[15];
char company[20];
char supplier[30];
char mediname[20];
char info[1000];
char mediid [30];
};
const char* supplier_format = "\n\tSupplierID:\t%s\n\tSupplierName:\t%s\n\tMobileNumber:
\t%s\n\tCompany:\t%s\n";
//Anlegen eines Structs für die Zulieferer
struct Supplier{
char supplierid[30];
char suppliername[30];
char mobno[15];
char company[50];
};
const char* customer_format = "\n\tCustomerID:\t%s\n\tCustomerName:\t%s\n\tMobileNumber:
\t%s\n";
//Anlegen eines Structs für die Kunden
struct Customer{
char customerid[30];
char customername[30];
char mobno[15];
};
// Struct um Kassenzettel einzuspeichern
struct bill{
char billid[30];
char mediname[30];
int medi_qty;
float price;
float total;
float newtotal;
float temptotal;
};
//Globale Variablen für Coupon und Prozent. Diese werden von der Main Funktion überschrieben,
wenn sie benutzt werden.
//Sie werden nur! in der Sellmed Funktion angewendet, um einen Discount auf einen Medizin
Verkauf anzuwenden.
#define SIZE 20
char coup[SIZE]={'n','o','c','o','u','p'};
float dis = 1.00;
//main menu Funktion:
void mainmenu();
//Kunde Funktionen Prototypen:
void customer();
void addcus();
void cuslist();
void searchcus();
void editcus();
void deletecus();
//Zulieferer Funktionen Prototypen:
void supplier();
void addsup();
void suplist();
void searchsup();
void editsup();
void deletesup();
//Medizin Funktionen Prototypen:
void medicine ();
void leave();
void addmed();
void sellmed();
void listing();
void searchmed();
void editmed();
void deletemed();
void pharwelc();
// Bestandsfunktionen Prototypen:
void searchstock();
void stock();
#endif /* MAINPROJECTNIKLASLOREK_H_ */
Upvotes: 1
Views: 171
Reputation: 1821
What you want is something like this:
#ifndef MAINPROJECTNIKLASLOREK_H_
#define MAINPROJECTNIKLASLOREK_H_
// Anlegen eines const char pointer um das Format des
// Medizinstructs festzulegen und später bei printf Ausgaben
// direkt anzuwenden
extern const char* medicine_format;
//Anlegen eines Structs für die Medizin
struct Medicine {
int quantity;
float price;
char expdate[15];
char company[20];
char supplier[30];
char mediname[20];
char info[1000];
char mediid [30];
};
extern const char* supplier_format;
// Anlegen eines Structs für die Zulieferer
struct Supplier{
char supplierid[30];
char suppliername[30];
char mobno[15];
char company[50];
};
extern const char* customer_format;
// Anlegen eines Structs für die Kunden
struct Customer{
char customerid[30];
char customername[30];
char mobno[15];
};
// Struct um Kassenzettel einzuspeichern
struct bill {
char billid[30];
char mediname[30];
int medi_qty;
float price;
float total;
float newtotal;
float temptotal;
};
// Globale Variablen für Coupon und Prozent. Diese werden von
// der Main Funktion überschrieben, wenn sie benutzt werden.
// Sie werden nur! in der Sellmed Funktion angewendet, um
// einen Discount auf einen Medizin Verkauf anzuwenden.
#define SIZE 20
char coup[SIZE] = { 'n', 'o', 'c', 'o', 'u', 'p' };
float dis = 1.00;
// Main menu Funktion:
extern void mainmenu(*actual parameters go here*);
// Kunde Funktionen Prototypen:
extern void customer(*actual parameters go here*);
extern void addcus(*actual parameters go here*);
extern void cuslist(*actual parameters go here*);
extern void searchcus(*actual parameters go here*);
extern void editcus(*actual parameters go here*);
extern void deletecus(*actual parameters go here*);
// Zulieferer Funktionen Prototypen:
extern void supplier(*actual parameters go here*);
extern void addsup(*actual parameters go here*);
extern void suplist(*actual parameters go here*);
extern void searchsup(*actual parameters go here*);
extern void editsup(*actual parameters go here*);
extern void deletesup(*actual parameters go here*);
// Medizin Funktionen Prototypen:
extern void medicine(*actual parameters go here*);
extern void leave(*actual parameters go here*);
extern void addmed(*actual parameters go here*);
extern void sellmed(*actual parameters go here*);
extern void listing(*actual parameters go here*);
extern void searchmed(*actual parameters go here*);
extern void editmed(*actual parameters go here*);
extern void deletemed(*actual parameters go here*);
extern void pharwelc(*actual parameters go here*);
// Bestandsfunktionen Prototypen:
extern void searchstock(*actual parameters go here*);
extern void stock(*actual parameters go here*);
#endif /* MAINPROJECTNIKLASLOREK_H_ */
Then you put the actual string initializers in the most appropiate source file. For example, if all the functions under the "Medezine" prototypes are in medezine.c
, then perhaps this should go in that same source file:
const char* medicine_format = "\n\tMediID:%s\n"
"\tMediName:%s\n\tQuantity:%d\n\tPrice:%.2f\n"
"\tExp.Date:%s\n\tCompany:%s\n\tSupplier:%s\n"
"\tInfo:%s\n";
As pointed out by @user3386109 above, you should also include complete parameter list with each function prototype.
Upvotes: 1
Reputation: 123558
The problem is that you have a bunch of global variables in your header file. When you compile each .c
file that includes that header, the resulting object file has its own definition of those variables. When you try to link the object files into a single executable, all those variable definitions conflict with each other.
The right answer is to not use global variables - functions should communicate through parameters and return values, not through globals. Using globals destroys the ability to modularize code as you are attempting to do.
Go through all of the functions in your program and ask two questions:
What information does this function need to perform all of its tasks? - the answer to this question will be your input arguments.
What data or change of state does the caller expect from this function? - the answer to this question will be your return value and/or any output arguments.
Let's take the customer
function as an example. Since you haven't posted the definition of the function I'm having to guess, but I'm assuming it displays customer data using the format string. I'm guessing it just writes to standard output, but it would be handy to write it to a file as well. So, for customer
, we're going to assume that the answers to question 1 are:
struct Customer
;and the answer to question 2 is "nothing", since it's strictly an output function.
So, the declaration of customer
in the header file becomes:
void customer( struct Customer, FILE * );
and its definition in the source file becomes
void customer( struct Customer c, FILE *stream )
{
const char* customer_format = "\n\tCustomerID:\t%s\n\tCustomerName:\t%s\n\tMobileNumber:\t%s\n";
fprintf( stream, customer_format, c.customerid, c.customername, c.mobno );
}
Somewhere in your main
file, you will have an instance of struct Customer
defined, so you'd call it as:
int main( void )
{
...
struct Customer c;
... // assume data is read into c here
customer( c, stdout );
...
}
Similarly, we can look at addcus
. The answers to question 1 will be
and the answers to question 2 will be
To indicate whether the input operation was successful we'll have the function return true
or false
. The function needs a place to store the input data - the caller will provide that by passing a pointer to a struct Customer
object. Thus, our declaration in the header file will be
bool addcus( struct Customer *, FILE * );
and the definition in the .c file will be
bool addcus( struct Customer *c, FILE *stream )
{
if ( stream == stdin )
fprintf( "Enter customer ID: " );
if ( !fgets( c->customerid, sizeof c->customerid, stream ) )
// input error - for now, we'll just return false
return false;
// repeat for customer name and mobile number
// if everything is read successfully, return true
return true;
}
So now we can update our main
function a little bit:
int main( void )
{
...
struct Customer c;
if ( addcus( &c, stdin ) )
customer( c, stdout );
...
}
You need to do that for every function in your program.
These are just examples, and may not reflect what you intend for your code to do. But it should illustrate the steps you need to take to modularize your code.
Upvotes: 3
Reputation: 43327
const char* supplier_format =
You can't put that stuff into header files. The header files should contain only extern const char* supplier_format;
where the initialization is in exactly one C file.
I went over the whole header file; assuming that the header file is enough to describe the problem, there's a few instances of this exact problem and nothing else. The struct and function declarations need no correction.
Upvotes: 4