Мультисписок имеет несколько указателей «next» и позволяет собирать несколько (до N) не связанных друг с другом списков по разным признакам, не дублируя полезной нагрузки.
typedef enum {
LI_A, LI_B, LI_N
} ListIndex;
enum { LEN = 40 };
typedef struct {
Entry* next[LI_N];
char name[LEN];
} Entry;
typedef Entry* PEntry;
PEntry heads[LI_N], tails[LI_N]; // считаем, что = NULL
int isIn(ListIndex aIndex, Entry* aEntry)
{
return (aEntry->next[aIndex] || tails[aIndex] == aEntry);
}
void addExisting(ListIndex aIndex, Entry* aEntry)
{
/* Уже есть? Поскольку такой код чреват ошибками, лучше всё же проверить */
if (isIn(aIndex, aEntry))
return;
if (tails[aIndex]) {
tails[aIndex]->next = aEntry;
tails[aIndex] = aEntry;
} else {
heads[aIndex] = tails[aIndex] = aEntry;
}
}
Entry* addNew(ListIndex aIndex, char* aName)
{
int i;
Entry* newEntry = (Entry*)malloc(sizeof(Entry));
strncpy(entry->name, aName, LEN);
entry->name[LEN-1] = '\0';
for (i = 0; i < LI_N, ++i)
entry->next[i] = NULL;
addExisting(aIndex, entry);
return entry;
}
/* closure — т.н. замыкание, передача контекста, из которого была
вызвана функция, вызывающая callback */
typedef void(*ListCallback)(Entry* aEntry, void* aClosure);
void traverseList(ListIndex aIndex, ListCallback aCallback, void* aClosure)
{
Entry* entry = heads[aIndex];
while (entry) {
aCallback(aEntry, aClosure);
entry = entry->next[aIndex];
}
}
О замыкании можно прочитать тут:
Для чего нужны замыкания в C++ и как вы их используете?