The typical approach is to provide an opaque pointer. But this means that all the functions that make up the interface of your library must either accept a pointer parameter or return a pointer that is never dereferenced by the caller.
So for example, you could provide a header like this:
Code:
#ifndef LINKED_LIST__HH
#define LINKED_LIST__HH
typedef struct linked_list *LINKED_LIST;
void add_head(LINKED_LIST, int);
void add_tail(LINKED_LIST, int);
void display_linked_list(LINKED_LIST);
void free_linked_list(LINKED_LIST);
LINKED_LIST create_linked_list(void);
#endif
Then in your source file, you would have:
Code:
#include "linked_list.h"
#include "node.h"
struct linked_list {
NODE_PTR head;
NODE_PTR tail;
};
void add_head(LINKED_LIST list, int value)
{
// ...
}
// ... etc ...
In this case I chose to make LINKED_LIST be an alias for struct linked_list* because from the library user's perspective, the fact that it is a pointer is irrelevant. However, instead of NODE_PTR, I would suggest using the pointer notation directly: why say NODE_PTR when you can just say NODE* and it is therefore certain at a glance that it is a pointer?