SaltyCrane Blog — Notes on JavaScript and web development

How to share non-global C data structures

My goal is to share C data structures without using global variables. I have one function that will fill the data structure and other functions that will use and optionally modify the data. I would also like the data structure definition to be in the same file as the function that fills it. (It looks like this last requirement requires pointers to pointers and a malloc so I will abandon it. See this thread in the comp.lang.c newsgroup.)

My solution is to pass pointers to structures to functions as described here: http://irc.essex.ac.uk/www.iota-six.co.uk/c/h4_structs_part_3.asp Here is my implementation and notes:

main.c:
main.c contains the main function which calls the other functions that operate on the data structure. It also defines (allocates memory) for the data structure at the file level. The data structure is declared using the static keyword so that it will have static duration (i.e. it will exist from program start to finish), but it will have internal linkage (i.e. it won't be global). (For more information on declarations see http://www-ccs.ucsd.edu/c/declare.html The address operator, &, is used to create a pointer to the data structure which is passed to the other functions.
#include "defs.h"
#include "get_data.h"
#include "use_data.h"

static DATA data;

int main()
{
    get_data(&data;);
    modify_data(&data;);
    display_data(&data;);
 
    return 0;
}
defs.h:
defs.h contains the combined structure data type declaration and typedef declaration to create the new type name, DATA. (See my notes on struct and typedef.) It is included in all the files that declare the data structure or a pointer to the data structure.
#ifndef DEFS_H_
#define DEFS_H_

typedef struct 
{
    int item1;
    int item2;
    float item3;
    float item4;
} DATA;

#endif /*DEFS_H_*/
get_data.c:
get_data.c contains the function to initially fill the data structure. It is passed a pointer to the data structure defined in main.c. It uses the structure pointer operator, ->, to access the members of the structure pointed to by data_ptr. data_ptr is the only local variable in this function-- the data structure being filled is the same one that was defined in main.c.
#include "defs.h"

int get_data(DATA *data_ptr)
{
    data_ptr->item1 = 1;
    data_ptr->item2 = 2;
    data_ptr->item3 = 3.0;
    data_ptr->item4 = 4.0;
 
    return 0;
}
use_data.c:
use_data.c contains the functions that use and modify the data in the data structure. They are both passed a pointer to the structure similar to get_data.c.
#include <stdio.h>
#include "defs.h"

int modify_data(DATA *data_ptr)
{
    data_ptr->item2 += 1;
    data_ptr->item4 += 1.0;
 
    return 0;
}

int display_data(DATA *data_ptr)
{
    printf("data.item1: %d\n", data_ptr->item1);
    printf("data.item2: %d\n", data_ptr->item2);
    printf("data.item3: %f\n", data_ptr->item3);
    printf("data.item4: %f\n", data_ptr->item4);
 
    return 0;
}
get_data.h
get_data.h and use_data.h contain the function declarations (function prototypes) and should be included wherever the functions are used.
#ifndef GET_DATA_H_
#define GET_DATA_H_

int get_data(DATA *data_ptr);

#endif /*GET_DATA_H_*/
use_data.h
#ifndef USE_DATA_H_
#define USE_DATA_H_

int modify_data(DATA *data_ptr);
int display_data(DATA *data_ptr);

#endif /*USE_DATA_H_*/
Output:
Running the program produces the following output:
data.item1: 1
data.item2: 3
data.item3: 3.000000
data.item4: 5.000000
Other notes:
Header files should only contain declarations. They should not contain variable definitions because if the header file is included in multiple locations there would be multiple definitons of the same variable. (See this thread in the comp.lang.c newsgroup.)

Diagram:


Revision 2 based on comments from this thread on the comp.lang.c newsgroup:


Revision 3: Updated based on more comments from the newsgroup. Also, I think my original #includes were OK.

Comments