views:

92

answers:

1

What are some clever (not ordinary) ways of implementing data structures in C, and what are some data structures that should be used more often?

For example, what is the most effective way (generating minimal overhead) to implement a directed and cyclic graph with weighted edges in C?
I know that we can store the distances in an array as is done here, but what other ways are there to implement this kind of a graph?

+1  A: 

Answering your first question, I recommend to encapsulate your structures using opaque pointers (a.k.a Handles).

For example, you may declare a handle to a linked list (here MS-like naming):

typedef struct linked_list_t* HLINKEDLIST;

We assume that linked_list_t is a generic one (composed of void pointers).

This way you can hide what a "handle" to a linked list is, or in what form is implemented (information hiding):

HLINKEDLIST LinkedListCreate();
LinkedListAdd(LLELEMENT v);
LinkedListCopy(HLINKEDLIST dst, const HLINKEDLIST src);

Handle subtypes are also commonly defined, such as PHLINKEDLIST (pointer to a linked list handle).

Related types can also be defined for convenience (and to use the limited information hiding available in C). e.g: the linked list element type can be defined as

typedef void* LLELEMENT;

There are good books on Data Structures in C to check. This is good: http://www.amazon.com/Interfaces-Implementations-Techniques-Creating-Reusable/dp/0201498413

Also note that LLELEMENT is actually compatible with void* so if you are defining other type def as:

typedef void* SYSTEMDATA;

SYSTEMDATA is compatible with LLELEMENT, so the compiler won't complain on:

int QuerySystemData(SYSTEMDATA* sd);

and calling:

QuerySystemData(lle);

where lle is of type LLELEMENT.

This type checking can be enforced encapsulating simple members in structs. If I don't remember bad, declaring STRICT in a program using windows.h causes handles to be type-safer (incompatible between). Definitions like the following are common:

typedef struct __HWND 
{ 
int __handle; 
} __HWND; 

typedef __HWND* HWND; 

If the simpler definitions were:

typedef int HWND;
typedef int HBITMAP;

The two handles would be type compatible and interchangeable on functions expecting to work with windows and functions expecting to work with bitmaps (potential horrible bugs).

Hernán
Yin Zhu