Vous essayez de regrouper le code selon la structure. Le regroupement en C se fait par fichier. Vous mettez toutes les fonctions et les variables internes dans un header ou un en-tête et un fichier objet ".o" compilés à partir d'un fichier source C.
Il n'est pas nécessaire de réinventer l'orientation objet à partir de zéro pour un programme en C, qui n'est pas un langage orienté objet.
J'ai déjà vu cela auparavant. C'est une chose étrange. Les codeurs, certains d'entre eux, ont une aversion pour passer un objet qu'ils veulent modifier dans une fonction pour le modifier, même si c'est la façon standard de le faire.
Je blâme le C++, car il a caché le fait que l'objet de la classe est toujours le premier paramètre d'une fonction membre, mais il est caché. Ainsi, on a l'impression qu'il ne passe pas l'objet dans la fonction, même si c'est le cas.
Client.addClient(Client& c); // addClient first parameter is actually
// "this", a pointer to the Client object.
Le C est flexible et peut accepter de passer des choses par référence.
Une fonction C ne renvoie souvent qu'un octet ou un int d'état et celui-ci est souvent ignoré. Dans votre cas, une forme appropriée pourrait être
/* add client to struct, return 0 on success */
err = addClient( container_t cnt, client_t c);
if ( err != 0 )
{
fprintf(stderr, "could not add client (%d) \n", err );
}
addClient serait dans Client.h ou Client.c