The use of various header files, and code/implementation files separate and apart from the application file is done to promote maintainability and reuse of code. By collecting all related functions, variables and data structures in a single file, we prevent having to duplicate that code in every subsequent application we write.
Take for example your situation where you will be developing routines related to matrices or arrays. This scheme allows you to collect the common routines dealing with your arrays into a single file, say arrays.c
. Now regardless of how many more programs you write, you have a common file that contain your array routines. Now if you write 5 more applications that need your array routines, you have them ready to go in arrays.c
.
For maintainability, let's say you now have a more efficient way of handling input from a file to your array. Instead of having to go back and update the read_array
function in 5 different application program files, you simply update the one read_array
function in arrays.c
and you have accomplished updating that routine for all applications that use it.
How does the header
file fit in? In order to use your array functions in other applications, the applications need a common way of including the code to make it available for use. That is done by including your arrays.h
header file in each application that needs it. OK, so what goes in arrays.h
and what goes in arrays.c
? Your header files will include the header files, function declarations, data structures and variables
for your array routines that are necessary to implement the function definitions
contained in arrays.c
. That way any application that wishes to make user of your array routines need only include the line #include "arrays.h"
at the beginning of its file to have access to your array functions contained in arrays.c
An example (in C) will help sort things out. Say you have several array functions that read lines in a text file into strings read_array
, print the lines prn_array
and then frees the memory used by the array and strings free_array
. You have collected your array functions in array.c
. (we know we will include array.h
at the top.) So, for example:
#include "array.h"
char **read_array (char *filename)
{
char *buffer = NULL;
size_t len = 0;
ssize_t read;
char **array = NULL;
int cnt = 0;
FILE *fp;
fp = fopen (filename, "r"); //open file , read only
if (!fp) {
fprintf (stderr, "failed to open file for reading\n");
return NULL;
}
array = calloc (AMAX, sizeof (*array) * AMAX); /* allocate pointers, set NULL */
while ((read = getline (&buffer, &len, fp)) != -1) { /* read each line */
if (cnt == AMAX) {
fprintf (stderr, "Error: AMAX reached\n");
break;
/* you will realloc *array here in real life */
}
if (buffer[read-1] == '\n') { /* strip newline */
buffer[read-1] = 0;
read -= 1;
}
array[cnt] = strdup (buffer); /* copy buffer to array[cnt] */
cnt++; /* increment counter */
}
fclose (fp); /* close file stream (fp) */
return array;
}
void prn_array (char **array)
{
register int j = 0;
while (array[j]) {
printf (" array[%d]: %s\n", j, array[j]);
j++;
}
}
void free_array (char **array)
{
register int j = 0;
while (array[j]) { /* for each allocated string */
free (array[j]); /* free pointer to string */
j++;
}
free (array); /* free array */
}
Now let's create our header. We collect our function declarations
along with any variables
or data structures
used and also include the system headers
and any other included header files
required by our functions in array.h
:
#ifndef MY_ARRAY_H
#define MY_ARRAY_H 1
/* headers required for array.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define AMAX 100
/* function declaration */
char **read_array (char *filename);
void prn_array (char **array);
void free_array (char **array);
#endif /* MY_ARRAY_H */
Notice we have wrapped the contents of our header inside a test #ifndef MY_ARRAY_H
which just asks the compiler if MY_ARRAY_H
is defined yet, ifndef
(if not defined), we let the compiler know that everything that follows our #define
until we reach the end of the if statement #endif
we are defining as MY_ARRAY_H
so that if another file tries to include the same header -- the compiler knows it already has it and doesn't need to include it again. (not required, but we also give our define of MY_ARRAY_H
the value 1
)
So how do we put our custom header array.h
and our custom functions for handling arrays in arrays.c
to work for us? We write an application that makes use of the functions in arrays.c
and to declare all the functions in arrays.c
in our application, we simply include array.h
in our application. (called application.c
below):
#include <stdio.h>
#include "array.h" /* include array.h */
int main (int argc, char *argv[]) {
if (argc < 2) {
printf ("filename.csv please...\n");
return 1;
}
char **my_array = NULL; /* declare pointers */
my_array = read_array (argv[1]); /* call read_array */
prn_array (my_array); /* call prn_array */
free_array (my_array); /* call free_array */
return 0;
}
compile the application.c and array.c files:
gcc -Wall -Wextra -o application application.c array.c
run it on any short text file (less than 100 lines)
$ ./application input.txt
array[0]: 1. This is a simple input file with line numbers
array[1]: 2. for use with application showing the use of
array[2]: 3. header file: array.h
array[3]: 4. array functions defined in: array.c
array[4]: 5. (blank)
array[5]: 6. compiled with the following:
array[6]: 7. gcc -Wall -Wextra -o application application.c array.c
array[7]: 8. --------
array[8]: 9. Now you know!
Now you can see the benefit of creating a separate file holding the related functions, variables, and data structures we will use and creating a header file. We can reuse that code in any application we like simply by including the header file arrays.h
in our application. We can update and maintain all our array functions in one place and updating our arrays.c
will update all other applications that make use of that code.
I know I have left much out, but make sure you are solid on these concepts. They are fundamental to working with multiple source files and includes in C/C++.