/* File: linked_list_str.c * * Purpose: Implement a sorted linked list of strings with ops Insert * in alphabetical order, Print, Member, Delete, Free_list. * * Input: Single character lower case letters to indicate operators, * followed by arguments needed by operators. * Output: Results of operations. * * Compile: gcc -g -Wall -o linked_list_str linked_list_str.c * (See note 2.) * * Run: ./linked_list_str * * Notes: * 1. Repeated strings are *not* allowed in the list * 2. DEBUG compile flag used. To get debug output compile with * -DDEBUG command line flag. */ #include #include #include const int STRING_MAX=100; /* Note that struct XXX definition allows us to use * recursive type definition */ struct list_node_s { char* data; struct list_node_s* next_p; }; struct list_node_s* Insert(char string[], struct list_node_s* head_pp); void Print(struct list_node_s* head_p); int Member(char string[], struct list_node_s* head_p); struct list_node_s* Delete(char string[], struct list_node_s* head_p); struct list_node_s* Free_list(struct list_node_s* head_p); int Is_empty(struct list_node_s* head_p); char Get_command(void); void Get_string(char string[]); void Free_node(struct list_node_s* node_p); struct list_node_s* Allocate_node(int size); /*-----------------------------------------------------------------*/ int main(void) { char command; char string[STRING_MAX]; struct list_node_s* head_p = NULL; /* start with empty list */ command = Get_command(); while (command != 'q' && command != 'Q') { switch (command) { case 'i': case 'I': Get_string(string); head_p = Insert(string, head_p); break; case 'p': case 'P': Print(head_p); break; case 'm': case 'M': Get_string(string); Member(string, head_p); /* ignoring return value */ break; case 'd': case 'D': Get_string(string); head_p = Delete(string, head_p); break; case 'f': case 'F': head_p = Free_list(head_p); break; default: printf("There is no %c command\n", command); printf("Please try again\n"); } command = Get_command(); } Free_list(head_p); return 0; } /* main */ /*-----------------------------------------------------------------*/ /* Function: Allocate_node * Purpose: Allocate storage for a list node * Input arg: size = number of chars needed in data member (including * storage for the terminating null * Return val: Pointer to the new node */ struct list_node_s* Allocate_node(int size) { struct list_node_s* temp_p; temp_p = malloc(sizeof(struct list_node_s)); temp_p->data = malloc(size*sizeof(char)); temp_p->next_p = NULL; return temp_p; } /* Allocate_node */ /*-----------------------------------------------------------------*/ /* Function: Insert * Purpose: Insert new node in correct alphabetical location in list * Input arg: string = new string to be added to list * head_p = pointer to head of list * Return val: Possibly updated pointer to head of list * Note: If the string is already in the list, print a message * and return, leaving list unchanged */ struct list_node_s* Insert(char string[], struct list_node_s* head_p) { struct list_node_s* curr_p = head_p; struct list_node_s* pred_p = NULL; struct list_node_s* temp_p; while (curr_p != NULL && strcmp(curr_p->data, string) < 0) { pred_p = curr_p; curr_p = curr_p->next_p; } if ( curr_p == NULL || strcmp(curr_p->data,string) > 0 ) { temp_p = Allocate_node(strlen(string) + 1); strcpy(temp_p->data, string); temp_p->next_p = curr_p; if (pred_p == NULL) head_p = temp_p; else pred_p->next_p = temp_p; } else if (strcmp(curr_p->data,string) == 0) { printf("%s is already in the list\n", string); } return head_p; } /* Insert */ /*-----------------------------------------------------------------*/ /* Function: Print * Purpose: Print the contents of the nodes in the list * Input arg: head_p = pointer to first node in list */ void Print(struct list_node_s* head_p) { struct list_node_s* curr_p = head_p; printf("list = "); while (curr_p != NULL) { printf("%s ", curr_p->data); curr_p = curr_p->next_p; } printf("\n"); } /* Print */ /*-----------------------------------------------------------------*/ /* Function: Member * Purpose: Search list for string * Input args: string = string to search for * head_p = pointer to first node in list * Return val: 1, if string is in the list, 0 otherwise */ int Member(char string[], struct list_node_s* head_p) { struct list_node_s* curr_p; curr_p = head_p; while (curr_p != NULL && strcmp(curr_p->data,string) < 0) curr_p = curr_p->next_p; if (curr_p == NULL || strcmp(curr_p->data,string) > 0) { printf("%s is not in the list\n", string); return 0; } else { printf("%s is in the list\n", string); return 1; } } /* Member */ /*-----------------------------------------------------------------*/ /* Function: Free_node * Purpose: Free storage used by a node of the list * In/out arg: node_p = pointer to node to be freed */ void Free_node(struct list_node_s* node_p) { free(node_p->data); free(node_p); } /* Free_node */ /*-----------------------------------------------------------------*/ /* Function: Delete * Purpose: Delete node containing string. * Input arg: string = string to be deleted * head_p = pointer to head of list * Return val: Possibly updated pointer to head of list * Notes: If the string is in the list, it will be unique. So * at most one node will be deleted. If the string isn't * in the list, the function just prints a message and * returns, leaving the list unchanged. */ struct list_node_s* Delete(char string[], struct list_node_s* head_p) { struct list_node_s* curr_p = head_p; struct list_node_s* pred_p = NULL; /* Find string */ while (curr_p != NULL && strcmp(curr_p->data,string) < 0) { pred_p = curr_p; curr_p = curr_p->next_p; } if (curr_p != NULL && strcmp(curr_p->data, string) == 0) { if (pred_p == NULL) { /* first element in list */ head_p = curr_p->next_p; # ifdef DEBUG printf("Freeing %s\n", string); # endif Free_node(curr_p); } else { pred_p->next_p = curr_p->next_p; # ifdef DEBUG printf("Freeing %s\n", string); # endif Free_node(curr_p); } } else { printf("%s isn't in the list\n", string); } return head_p; } /* Delete */ /*-----------------------------------------------------------------*/ /* Function: Free_list * Purpose: Free storage used by list * Input arg: head_p = pointer to head of list * Return val: NULL pointer (which is assigned to head of list) */ struct list_node_s* Free_list(struct list_node_s* head_p) { struct list_node_s* curr_p; struct list_node_s* following_p; curr_p = head_p; while (curr_p != NULL) { following_p = curr_p->next_p; # ifdef DEBUG printf("Freeing %s\n", curr_p->data); # endif Free_node(curr_p); curr_p = following_p; } return NULL; // New value for head_p } /* Free_list */ /*-----------------------------------------------------------------*/ /* Function: Is_empty * Purpose: Determine whether the list is empty * Input arg: head_p = pointer to first node in the list * Return val: 1 if the list is empty, 0 otherwise */ int Is_empty(struct list_node_s* head_p) { if (head_p == (struct list_node_s*) NULL) return 1; else return 0; } /* Is_empty */ /*-----------------------------------------------------------------*/ /* Function: Get_command * Purpose: Find and return the next non-whitespace character in * the input stream * Return val: The next non-whitespace character in stdin */ char Get_command(void) { char c; printf("Please enter a command (i, d, m, p, f, q): "); /* Put the space before the %c so scanf will skip white space */ scanf(" %c", &c); return c; } /* Get_command */ /*-----------------------------------------------------------------*/ /* Function: Get_string * Purpose: Read the next string in stdin (delimited by whitespace) * Out arg: string = next string in stdin */ void Get_string(char string[]) { printf("Please enter a string: "); scanf("%s", string); } /* Get_string */