These are list manipulation operations you saw in one of the tutorials. Tutorial comments are written by my collegue Rosenthal. IK =========================================================================== In many programming languages, linked list routines have a bunch of annoying special cases around the head of the list. To insert in the middle of a linked list, or at the end, you can assign the 'next' member of the element you're inserting after to be the pointer to the new element, and the 'next' member of your new element to be the former 'next' value of the element you're inserting after (hm, this sounds unclear.. anyway, you know how a linked list insertion works). Whereas to insert at the head of the list, you do new->next = head; and head = new;. It's a special case. For deletion, the special cases look even more grotty, to me. In C, this can be made uniform with an extra level of indirection. Here is an example program which does both styles of linked list manipulation. Remember that the 'struct' and pointers and malloc are all new to them (I'm in the middle of it now, going to finish it in lecture today). So I think it's worth doing the "old style" version first, then the new one. You don't want to present the main program to them. I just wrote that to test it. You might want to think of an appropriate example, or just present a couple of insert and delete calls, they can get it. Perhaps do the printall() function first. And search(). These, basically, show what we want the linked list structure to be, whereas insert and delete are the functions which build it. After that's clear, do insert and delete. Don't do the "#ifdef OLDSTYLE" line and all that... just present the old versions, in some detail, then the new versions, in more detail. I think that it's possible that this "new version" style might be new to some of you. So please don't hesitate to ask about it. I think it's a good example for understanding structs and pointers better, and also I think that any time we see a host of special cases like we do in the traditional linked-list code, we should see if we can't get rid of the special cases. Which in this case we do with an extra level of indirection. That is, "{something}->next" and "head" are different, but they're of the same type (pointer to struct item), so a pointer to either one of them can be made uniform. I actually had a bug in the handling of insertions at the head of a non-empty list in my first draft of this program. Too many special cases, too many possibilities of error. My "new style" version ran correctly the first time, because it's simpler, easier to get right, better. Another note about this: You can only have one linked list, in the whole program, with the following code. This is worth pointing out (briefly) as part of their understanding of how C doesn't have classes. One way of looking at the difference between modules and classes is that with classes, you can automatically make any number of the data objects. (Although you can defeat this by using "class variables" ('static' class members in C++ or java).) -- #include #include int main() { int i; extern void init(), insert(int key, int data), delete(int key), printall(); extern int search(int key); init(); insert(38, 3); insert(20, 2); insert(5, 0); insert(22, 2); insert(46, 4); printall(); delete(22); printall(); delete(5); printall(); while (scanf("%d", &i) == 1) printf("%d\n", search(i)); return 0; } /* here is the part worth writing on the blackboard */ struct item { int key; int data; struct item *next; }; static struct item *head = NULL; /* (you'll have to explain "static" briefly -- like "private" in java) */ /* (you can probably mostly just speak the comments rather than writing them) */ void init() { head = NULL; } void printall() { struct item *p; for (p = head; p; p = p->next) printf("%d: %d\n", p->key, p->data); } int search(int key) { struct item *it, *prev; for (it = head; it && it->key < key; it = it->next) prev = it; if (it && it->key == key) return it->data; else return -1; } #ifdef OLDSTYLE void insert(int key, int data) { struct item *new, *prev; /* create the new item */ new = (struct item *)malloc(sizeof(struct item)); /* (should check for NULL return, but omit for this example) */ new->key = key; new->data = data; /* find the node it goes after; NULL if it goes at the front */ if (head == NULL || head->key >= key) { prev = NULL; } else { for (prev = head; prev->next && prev->next->key < key; prev = prev->next) ; } /* link it in */ if (prev == NULL) { /* goes at the head of the list */ new->next = head; head = new; } else { /* goes after 'prev' */ new->next = prev->next; prev->next = new; } } void delete(int key) { struct item *it, *prev = NULL; /* find it */ for (it = head; it && it->key < key; it = it->next) prev = it; if (it && it->key == key) { if (prev) { /* delete an item which is not first */ prev->next = it->next; } else { /* delete the head */ head = it->next; } free((char *)it); } else { printf("error: %d not found\n", key); } } #else void insert(int key, int data) { struct item *new, **p; /* create the new item */ new = (struct item *)malloc(sizeof(struct item)); /* (should check for NULL return, but omit for this example) */ new->key = key; new->data = data; /* find the (struct item *) to place it at */ for (p = &head; *p && (*p)->key < key; p = &(*p)->next) ; /* link it in */ new->next = *p; *p = new; } void delete(int key) { struct item **p; /* find the (struct item *) which points to it */ for (p = &head; *p && (*p)->key < key; p = &(*p)->next) ; if (*p && (*p)->key == key) { struct item *old = *p; *p = (*p)->next; free((char *)old); } else { printf("error: %d not found\n", key); } } #endif *** (C) Alan Rosenthal ***