/* * linkedList.c * FINAL version * create, initialize, and free a simple Linked List * of dynamic structs */ #include #include #include #define MAX_NAME_LENGTH 10 typedef struct { char *name; int age; } Person; /* Person is now a data type */ /* typedef struct list_node * ListNodePtr; */ typedef struct list_node { Person data; struct list_node *next; } ListNode; /* ListNode is another data type */ void printList(ListNode *hd); void freeList(ListNode *hd); void fatalError(char *msg); void append(ListNode **hd, Person p); void appendRecur(ListNode **hd, Person p); void delete(ListNode **hd, char *nm); void deleteRecur(ListNode **hd, char *nm); /* I added this one after class, using the return value to delete */ ListNode* deleteRecurReturn(ListNode *hd, char *nm); int main(int argc, char *argv[]) { FILE *inFile; Person m; struct list_node *head = NULL; ListNode *tmp; /* doubles for new element pointer and iterator */ /* temp variables to read data from file */ char name[MAX_NAME_LENGTH]; int age; if (!(inFile = fopen("input.txt", "r"))) fatalError("Can't open input.txt"); /* Build list via insert at front with each name/age from infile */ while(fscanf(inFile,"%s %d",name,&age) == 2) { if ((tmp = (ListNode *)malloc(sizeof(ListNode))) == NULL) fatalError("malloc of tmp failed"); if ((tmp->data.name = (char *)malloc((strlen(name) + 1) * sizeof(char))) == NULL) fatalError("malloc of tmp->name failed"); strcpy(tmp->data.name,name); tmp->data.age = age; /* insert the new node in front of the current head node */ tmp->next = head; head = tmp; } fclose(inFile); printf("printing the list:\n"); printList(head); m.age = 23; m.name = (char *)malloc(strlen("Matt") + 1); strcpy(m.name, "Matt"); append(&head, m); m.age = 19; m.name = (char *)malloc(strlen("Shahriar") + 1); strcpy(m.name, "Shahriar"); appendRecur(&head,m); printList(head); deleteRecurReturn(head, "Mark"); printList(head); freeList(head); return 0; } /* Notice we use our incoming head pointer as an iterator! * We are not corrupting the real head in main - this is just a copy * Some folks like this style, some would rather use an explicit temp ptr */ void printList(ListNode *hd) { for ( ; hd != NULL; hd = hd->next) { printf("[%s,%d]", hd->data.name, hd->data.age); if (hd->next) printf(" -> "); } printf("\n"); } /* use recursion to free string and struct on the way back up the list. * Doing this going forward would be cutting our bridge off in front of us */ void freeList(ListNode *hd) { if (hd == NULL) return; freeList(hd->next); /* recurse to the end of list */ free(hd->data.name); /* free the string */ free(hd); /* then the struct */ } /* a convenient function to print a fatal error msg and exit the program * Note we don't bother cleaning up memory. It will be done for us * when our program exits. */ void fatalError(char *msg) { fprintf(stderr,"\nFATAL ERROR: %s!!\n\n", msg); exit(EXIT_FAILURE); } void append(ListNode **hd, Person p) {ListNode *temp; if (*hd == NULL) { *hd = (ListNode *)malloc(sizeof(ListNode)); (*hd)->data = p; (*hd)->next = NULL; } else { temp = *hd; while (temp->next) { temp = temp->next; } temp->next = (ListNode*)malloc(sizeof(ListNode)); temp->next->data = p; temp->next->next = NULL; } } void appendRecur(ListNode **hd, Person p) { if (*hd == NULL) { *hd = (ListNode *)malloc(sizeof(ListNode)); (*hd)->data = p; (*hd)->next = NULL; } else { appendRecur(&(*hd)->next, p); } } void delete(ListNode **hd, char *nm) {ListNode *temp, *prev; /* check for *hd == null */ if (strcmp((*hd)->data.name, nm) == 0) { temp = *hd; *hd = (*hd)->next; free(temp->data.name); free(temp); } else { prev = *hd; temp = (*hd)->next; while (temp && strcmp(temp->data.name,nm) != 0) { prev = temp; temp = temp->next; } if (temp) { prev->next = temp->next; free(temp->data.name); free(temp); } } } void deleteRecur(ListNode **hd, char *nm) {ListNode *temp; if (*hd) { if (strcmp((*hd)->data.name, nm) == 0) { temp = *hd; (*hd) = (*hd)->next; free(temp->data.name); free(temp); } else deleteRecur(&(*hd)->next, nm); } } ListNode* deleteRecurReturn(ListNode *hd, char *nm) /* note that the parameter is just a ListNode *, not a ** */ {ListNode *temp; if (hd != NULL) { if (strcmp(hd->data.name,nm) == 0) { temp = hd; hd = hd->next; free(temp->data.name); free(temp); } else hd->next = deleteRecurReturn(hd->next, nm); } return hd; }