In his book Patterns in C, Adam Petersen describes using a pointer to a struct, which is declared in a header file, to create a first-class abstract data-type:
/* Customer.h */
/* A pointer to an incomplete type (hides the implementation details). */
typedef struct Customer* CustomerPtr;
/* Create a Customer and return a handle to it. */
CustomerPtr createCustomer(const char* name, const Address* address);
/* Destroy the given Customer. All handles to it will be invalidated. */
void destroyCustomer(CustomerPtr customer);
The struct and the two functions are defined in Customer.c:
#include ”Customer.h”
#include <stdlib.h>
struct Customer
{
const char* name;
Address address;
size_t noOfOrders;
Order orders[42];
};
CustomerPtr createCustomer(const char* name, const Address* address)
{
CustomerPtr customer = malloc(sizeof * customer);
if(customer)
{
/* Initialize each field in the customer... */
}
return customer;
}
void destroyCustomer(CustomerPtr customer)
{
/* Perform clean-up of the customer internals, if necessary. */
free(customer);
}
The way I would organize my code is a bit different. The header file would declare the struct itself, not a pointer to it. Here is the way I was taught of coding something similar:
/* Customer.h */
struct Customer;
extern struct Customer* newCustomer(const char* name);
and declarations:
/* Customer.c */
struct Customer {
char name[CUSTNAMELENGTH +1];
};
struct Customer* newCustomer(const char* name) {
struct Customer* newCustomer;
newCustomer = malloc(sizeof(struct Customer));
/* initialize customer instance */
return newCustomer;
}
What is the practical difference between the two styles? Is there a potential problem with my way that I don't see? It seems to successfully encapsulate the object, and provide an interface similar to Petersen's design. When should I use his design rather than what I have been doing?