I am coding for a simple linked list , but facing a little problem. The program is like it is accepting name, age and DOB through user, and memory for it is dynamically allocated. After taking data from the user, it is searching a name, asked by user, if the name exists, it should print all the details related to it.
Here is my code-
//function declarations
struct node *initnode(char *, char *, char *);
void add(struct node *);
struct node *printnode(struct node *);
struct node *searchname(struct node *, char *);
struct node {
char name[25];
char age[10];
char dob[10];
struct node *next;
};
struct node *head = (struct node *) NULL;
struct node *initnode(char *name, char *age, char *dob1)
{
struct node *ptr;
ptr = (struct node *) malloc(sizeof(struct node));
if (ptr == NULL)
return (struct node *) NULL;
else {
strcpy(ptr->name, name);
strcpy(ptr->age, age);
strcpy(ptr->dob, dob1);
ptr->next = NULL;
return ptr;
}
}
struct node *printnode(struct node *ptr)
{
printf("Name -> %s\n", ptr->name);
printf("age -> %s \n", ptr->age);
printf("dob ->%s\n", ptr->dob);
return ptr;
}
void add(struct node *newp)
{
struct node *temp = (struct node *) malloc(sizeof(struct node));
if (head == NULL)
head = newp;
else {
for (temp = head; temp->next != NULL; temp = temp->next);
temp->next = newp;
temp = newp;
}
free(temp);
}
struct node *searchname(struct node *ptr, char *name1)
{
if (strcmp(name1, ptr->name) == 0) {
printf("\n name found \n");
printf("\n details are -\n");
printnode(ptr);
return ptr;
} else {
printf("\n name not found in the database \n");
}
}
int main()
{
char name[25];
char name1[25];
char rep;
char age[10];
char dob[10];
int i;
int flag = 1;
struct node *ptr;
do {
fflush(stdin);
while (flag != 0) {
printf("Enter name -- ");
gets(name);
for (i = 0; name[i] != '\0'; i++)
if (isdigit(name[i])) {
printf("Error in user input, name should be in alphabets\n");
flag = 1;
break;
}
else
flag = 0;
}
flag = 1;
while (flag != 0) {
printf("Enter age -- ");
scanf("%s", &age);
fflush(stdin);
for (i = 0; age[i] != '\0'; i++)
if (isalpha(age[i])) {
printf("Error in user input, age should be in numbers\n");
flag = 1;
break;
} else {
flag = 0;
}
}
flag = 1;
while (flag != 0) {
printf("Enter dob in DD/MM/YY format-- ");
scanf("%s", &dob);
fflush(stdin);
for (i = 0; dob[i] != '\0'; i++) {
if (isalpha(dob[i])) {
printf("Error in user input, dob should be in numbers\n");
flag = 1;
break;
} else
flag = 0;
}
}
flag = 1;
ptr = initnode(name, age, dob);
add(ptr);
printf("\n Do you want to continue?<Y/N>:\n ");
scanf("%s", &rep);
//rep = getchar();
}
while (rep == 'Y' || rep == 'y');
printf("\n do u want to search for a name in the database? <Y/N>:\n");
scanf("%s", &rep);
if (rep == 'Y' || rep == 'y') {
printf("Enter name you want to search-- ");
scanf("%s", &name1);
ptr = searchname(head, name1);
} else {
printf("\n goodbye \n");
}
do {
printf("\n do u want to search again? <Y/N>:\n");
scanf("%s", &rep);
if (rep == 'Y' || rep == 'y') {
printf("Enter name you want to search-- ");
scanf("%s", &name1);
ptr = searchname(head, name1);
} else {
printf("\n goodbye \n");
}
}
while (rep == 'Y' || rep == 'y');
return 0;
}
The issue is that it is searching for the first entry only and not others, can anyone help me to sort out this? I am compiling through "gcc".
At a first glance, your search function is only comparing one element, the head of the list.
After comparing one element you must go to the next element. This can either be done recursively or with a while:
Recursive use:
struct node *searchname(struct node *ptr, char *name1)
{
if (ptr==NULL) //Reached end of the list
{
printf("\n name not found in the database \n");
return NULL;
}
if (strcmp(name1, ptr->name) == 0) { //found the element
printf("\n name found \n");
printf("\n details are -\n");
printnode(ptr);
return ptr;
} else { //search next element
return searchname(ptr->next,name1); //this will call your function again for the next element on the list
}
}
While use:
struct node *searchname(struct node *ptr, char *name1)
{
struct node *aux; // usually i use an auxiliary pointer in order to avoid unwanted overwrite at my pointer.
aux = ptr;
while (aux!=NULL)
{
if (strcmp(name1, aux->name) == 0) { //found the element
printf("\n name found \n");
printf("\n details are -\n");
printnode(aux);
return aux;
}
else { //move pointer to next element
aux=aux->next;
}
}
//if it reaches this point, the element was not found
printf("\n name not found in the database \n");
return NULL;
}
Check your add function, it is wrong. Step mentally through it, and see what happens
to your pointer, and to the memory it points to.
What are the malloc and free used for in the add function?
Related
I am having issues searching a linked list in C. I manage to search and find an integer entry but am having problems with strings (first and last names). Basically, there are three functions that search a telephone directory for entries by first, last name and number. Would it be possible to display the entry when a search is found too? Please find the code below. Thanks for your help.
struct node {
char firstname[32];
char lastname[32];
int *number;
struct node *next;
}*head;
struct node *start=NULL;
struct node *getnode() {
return((struct node *)malloc(sizeof(struct node)));
}
void insert() {
struct node *temp,*nn;
nn=getnode();
temp=start;
while(temp->next!=NULL)
{
temp=temp->next;
}
printf("Enter First name:\n");
scanf("%s",&nn->firstname);
printf("Enter Last name:\n");
scanf("%s",&nn->lastname);
printf("Enter number:\n");
scanf("%d",&nn->number);
temp->next=nn;
nn->next=NULL;
display(start);
}
struct node *create() {
struct node *temp,*nn;
if(start!=NULL) insert();
else {
nn=getnode();
start=nn;
temp=start;
printf("Enter First name:\n");
scanf("%s",&nn->firstname);
printf("Enter Last name:\n");
scanf("%s",&nn->lastname);
printf("Enter number:\n");
scanf("%d",&nn->number);
nn->next=NULL;
}
}
void searchByFirstName() {
char *f;
struct node* temp, *nn;
temp = start;
while (temp != NULL){
printf("Enter First Name to be searched:\n"); scanf("%s",&f);
printf("%s", &f);
if (temp -> firstname == f){
printf ("\n Record Found!\n");
temp = temp -> next;
}else{
printf ("\n Record not found\n");
}
}
}
void searchByLastName() {
char *f;
struct node* temp, *nn;
temp = start;
if (temp != NULL){
printf("Enter Last Name to be searched:\n"); scanf("%s",&f);
printf("%s", &f);
if (temp -> lastname == f){
printf ("\n Record Found!\n");
temp = temp -> next;
}else{
printf ("\n Record not found\n");
}
}
}
void searchByNumber() {
int *l;
struct node* temp, *nn;
temp = start;
if (temp != NULL){
printf("Enter Number to be searched:\n"); scanf("%d",&l);
if (temp -> number == l){
printf ("\n Record Found!\n");
temp = temp -> next;
}else{
printf ("\n Record not found\n");
}
}
}
In C, you cannot just compare two strings (aka char *) using operator ==. When you work with strings in C, you can use the standard functions (#include <string.h>), like:
strcmp(temp->lastname, f) // returns 0 in case of a perfect match
2nd EDIT: added Pretty functions (last section) - examples of how printing messages could be modified.
EDIT: added free(l) in the searchByNumber2(), fixing a memory leak
For the thing you was asking for:
void searchByLastName() {
char f = char[32];
struct node* temp, *nn;
temp = start;
printf("Enter Last Name to be searched:\n"); scanf("%s",f);
printf("%s", f);
while (temp != NULL){//!we search through whole list
if (strcmp(temp -> lastname, f) == 0) {
printf ("\n Record Found!\n");
temp = temp -> next;
}else{
printf ("\n Record not found\n");
/*!you probably wanna pull this printf for after the loop;
I would either add bool Found and add if after the loop
or after the loop always print "search finished" or sth */
}
}
}
And two versions of fixed searching by numbers (the second uses int *l, as an example; the first uses int l and is cleaner)
void searchByNumber() {
int l;
struct node* temp, *nn;
temp = start;
printf("Enter Number to be searched:\n"); scanf("%d",&l);//&l is address of the int l
while (temp != NULL){
if (*(temp -> number) == l){//notice: temp->number is a pointer to int, not an int itself, l is an int here
printf ("\n Record Found!\n");
temp = temp -> next;
}else{
printf ("\n Record not found\n");
}
}
}
void searchByNumber2() {
int *l = malloc(sizeof int);
struct node* temp, *nn;
temp = start;
printf("Enter Number to be searched:\n"); scanf("%d",l);
while (temp != NULL){
if (*(temp -> number) == *l){//we want to compare int values, not their adresses, both temp->number and l are pointers here
printf ("\n Record Found!\n");
temp = temp -> next;
}else{
printf ("\n Record not found\n");
}
}
free(l);
}
Last edit
Note: this version of searchByLastNamePretty prints Found message the number of times the last name appears, and prints Finished message after a search.
On th other hand, searchByNumberPretty prints a Found message or a Not-Found message (only one message, always; doesn't matter if there is a lot of occurences of the number).
Use them as examples of what you could do. Analyze usage of bool Found.
void searchByLastNamePretty() {
char f = char[32];
struct node* temp, *nn;
temp = start;
printf("Enter Last Name to be searched:\n"); scanf("%s",f);
printf("%s\n", f); //better practice, to end printf with \n to flush it
while (temp != NULL){//!we search through whole list
if (strcmp(temp -> lastname, f) == 0) {
printf ("Record Found!\n");
temp = temp -> next;
}
printf("Search finished\n");
}
}
void searchByNumberPretty() {
int l;
struct node* temp, *nn;
temp = start;
printf("Enter Number to be searched:\n");
scanf("%d",&l);//&l is address of the int l
bool found = false;
while (temp != NULL && !found){//!we search till the first occurence
if (*(temp -> number) == l){//note: (temp->number) is a pointer to int, not an int
found = true;
temp = temp -> next;
}
}
if (found) {
printf("Record Found!\n");
}
else {
printf("Record not found\n");
}
}
I need to make a function that removes elements of a linked list (elements of the list are words) that contain a letter the user inputs. Basically, I have a .txt file that has random words in it, after loading the words into the linked list, I need to make several functions (this post is only dedicated for the 4th function from the menu), one of which is the function I'm having trouble with.
My idea was to make a separate function that will send 1 if the word contains the letter and 0 if it does not, then I made a function that goes through my linked list and using the first function checks if that element of the list contains the word, if it does then I remove it and move onto the next element.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Element Element;
struct Element
{
char word[50];
Element *next;
};
Element *load_file(Element *head)
{
char file[500];
scanf("%s", file);
Element *temp = head;
FILE* fp = fopen(file, "r");
if(fp == NULL)
{
printf("Error while loading file.");
return 0;
}
while(!feof(fp))
{
Element *newE = (Element*)malloc(sizeof(Element));
fscanf(fp, "%s", newE->word);
newE->next = NULL;
if(!temp)
{
head = temp = newE;
}
else
{
temp->next = newE;
temp = newE;
}
}
fclose(fp);
printf("\nFile loaded successfully\n");
return head;
}
int frequency(Element *head, char *word)
{
Element *temp = head;
int counter = 0;
while(temp != NULL)
{
if(strcmp(temp->word, word) == 0)
{
counter++;
}
temp = temp->next;
}
return counter;
}
int contains(char word[], char letter)
{
int end = strlen(word);
int flag = 0;
for(int i = 0; i < end-1; i++)
{
if(letter == word[i])
{
flag = 1;
break;
}
}
return flag;
}
Element *delete_word(Element *head, char letter)
{
Element *temp = head;
Element *before = NULL;
Element *newHead = head;
while(temp != NULL)
{
if(contains(temp->word, letter))
{
if(before == NULL)
{
newHead = temp->next;
free(temp);
temp = newHead;
}
else
{
before->next = temp->next;
free(temp);
temp = before->next;
}
}
else
{
before = temp;
temp = temp->next;
}
}
return newHead;
}
void printElement(Element *element)
{
printf("%s \n", element->word);
}
void printList(Element *head)
{
Element *temp = head;
while(temp != NULL)
{
printElement(temp);
temp = temp->next;
}
}
void meni()
{
printf("************** MENI **************\n");
printf("1. Loading text from file \n");
printf("2. Print all elements of the list \n");
printf("3. Frequency of a certain word \n");
printf("4. Delete words that contain a letter \n");
printf("5. Load the list into a file \n");
printf("6. Exit \n\n");
}
int main()
{
Element *head = NULL;
int option;
while(1)
{
meni();
scanf("%d", &option);
switch(option)
{
case 1:
{
printf("Input a name of the file: \n");
head = load_file(head);
break;
}
case 2:
{
printList(head);
break;
}
case 3:
{
char word[100];
printf("Input a word: ");
scanf("%s", word);
int num = frequency(head, word);
printf("%d\n", num);
break;
}
case 4:
{
char word[100];
printf("Input a word: ");
scanf("%s", word);
head = delete_word(head, word);
printList(head);
break;
}
case 5:
{
}
case 6:
{
return 0;
}
}
}
return 0;
}
For some reason, it makes no changes on the list whatsoever.
Your delete_word() function is declared as:
Element *delete_word(Element *head, char letter);
But you call it with a char*:
char word[100];
head = delete_word(head, word);
The menu option says Delete words that contain a letter but when the user selects that option, he/she is instructed to Input a word: (confusing).
You then send the address of the first char in word to the function. From that address one char is picked. It'll be random at best and it will most probably corrupt the stack (since you, by picking one char only, probably pick 1 byte out of 4 or 8).
You could make it work like this:
case 4:
{
char word[100];
printf("Input characters: ");
if(scanf("%s", word)==1) {
int len = strlen(word);
for(int i=0; i<len; ++i) {
head = delete_word(head, word[i]);
}
}
printList(head);
break;
}
This would allow the user to enter some characters and all words containing any of those would be removed.
I'm having a bit of trouble trying to create a new linked list of structures from an old one. The basis of the new linked list is that the dogs that belong to specific breed specified by the user will be added to the new list and all the ones from the old list will not be carried over. I don't have a problem getting one dog into the list but I think something is wrong with my code when I try to add multiple dogs. I assumed that when I created the second temp list that points to the list results that when I added to it it would modify results but that does not seem to be the case. Any direction would be appreciated.
The last function in the code struct container* list_of_breed(char* breed) is the one I seem to be having issues with. Everything else has been working as expected. I believe the else statement is where I seem to be going wrong since when there is only one dog that matches that breed it seems to be able to make the list from them.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#pragma warning(disable: 4996)
// used to create a linked list of containers, each contaning a "dog"
struct container {
struct dog *dog;
struct container *next;
} *list = NULL;
// used to hold dog information and linked list of "checkups"
struct dog {
char name[30];
char breed[30];
struct checkup *checkups;
};
// used to create a linked list of checkups containing "dates"
struct checkup {
char date[30];
struct checkup *next;
};
void flush();
void branching(char);
void helper(char);
void remove_all(struct container*);
void display(struct container*);
void add_dog(char*, char*);
struct dog* search_dog(char*);
void add_checkup(char*, char*);
struct container* list_of_breed(char*);
int main()
{
char ch = 'i';
printf("Dog Adoption Center\n\n");
do
{
printf("Please enter your selection:\n");
printf("\ta: add a new dog to the list\n");
printf("\ts: search for a dog on the list\n");
printf("\tc: add a checkup date for dog\n");
printf("\tb: display list of dogs of breed\n");
printf("\tq: quit\n");
ch = tolower(getchar());
flush();
branching(ch);
} while (ch != 'q');
remove_all(list);
list = NULL;
_CrtDumpMemoryLeaks();
return 0;
}
void flush()
{
int c;
do c = getchar(); while (c != '\n' && c != EOF);
}
void branching(char c)
{
switch (c)
{
case 'a':
case 's':
case 'r':
case 'c':
case 'l':
case 'b':
case 'n': helper(c); break;
case 'q': break;
default: printf("Invalid input!\n");
}
}
void helper(char c)
{
if (c == 'a')
{
char input[100];
printf("\nPlease enter the dog's info in the following format:\n");
printf("name:breed\n");
fgets(input, sizeof(input), stdin);
input[strlen(input) - 1] = '\0';
char* name = strtok(input, ":");
char* breed = strtok(NULL, ":");
struct dog* result = search_dog(name);
if (result == NULL)
{
add_dog(name, breed);
printf("\nDog added to list successfully\n\n");
}
else
printf("\nThat dog is already on the list\n\n");
}
else if (c == 's' || c == 'r' || c == 'c' || c == 'l')
{
char name[30];
printf("\nPlease enter the dog's name:\n");
fgets(name, sizeof(name), stdin);
name[strlen(name) - 1] = '\0';
struct dog* result = search_dog(name);
if (result == NULL)
printf("\nThat dog is not on the list\n\n");
else if (c == 's')
printf("\nBreed: %s\n\n", result->breed);
else if (c == 'c')
{
char date[30];
printf("\nPlease enter the date of the checkup:\n");
fgets(date, sizeof(date), stdin);
date[strlen(date) - 1] = '\0';
add_checkup(name, date);
printf("\nCheckup added\n\n");
}
}
else if (c == 'b')
{
char breed[30];
printf("\nPlease enter the breed:\n");
fgets(breed, sizeof(breed), stdin);
breed[strlen(breed) - 1] = '\0';
struct container* result = list_of_breed(breed);
printf("\nList of dogs with breed type %s:\n\n", breed);
display(result);
remove_all(result);
result = NULL;
}
}
void remove_all(struct container* dogs)
{
struct checkup* temp;
if (dogs != NULL)
{
remove_all(dogs->next);
while (dogs->dog->checkups != NULL)
{
temp = dogs->dog->checkups;
dogs->dog->checkups = dogs->dog->checkups->next;
free(temp);
}
free(dogs->dog);
free(dogs);
}
}
void display(struct container* dogs)
{
struct container* container_traverser = dogs;
if (container_traverser == NULL)
{
printf("\nThere are no dogs on this list!\n\n");
return;
}
while (container_traverser != NULL)
{
printf("Name: %s\n", container_traverser->dog->name);
printf("Breed: %s\n", container_traverser->dog->breed);
printf("Checkups on file: ");
struct checkup* ptr = container_traverser->dog->checkups;
if (ptr == NULL)
{
printf("No checkups documented.");
}
else
{
while (ptr != NULL)
{
printf("\n%s", ptr->date);
ptr = ptr->next;
}
}
printf("\n\n");
container_traverser = container_traverser->next;
}
}
void add_dog(char* name, char* breed)
{
struct dog *tempDog = (struct dog *) malloc(sizeof(struct dog));
strcpy(tempDog->name, name);
strcpy(tempDog->breed, breed);
struct container *tempCont = (struct container *) malloc(sizeof(struct container));
tempCont->dog = tempDog;
tempCont->next = list;
list = tempCont;
}
struct dog* search_dog(char* name)
{
struct container *temp = list;
while (temp != NULL) {
if (strcmp(temp->dog->name, name) == 0) {
return temp->dog;
}
temp = temp->next;
}
return NULL;
}
void add_checkup(char* name, char* date)
{
struct container *tempList = (struct container *) malloc(sizeof(struct container));
tempList = list;
struct checkup *tempCheck = (struct checkup *) malloc(sizeof(struct checkup));
while (tempList != NULL) {
if (strcmp(tempList->dog->name, name) == 0) {
strcpy(tempCheck->date, date);
tempList->dog->checkups = tempCheck;
}
tempList = tempList->next;
}
}
//THIS IS THE FUNCTION I AM HAVING ISSUES WITH SPECIFICALLY RETURNING MULTIPLE STRUCTURES TO THE LIST
struct container* list_of_breed(char* breed)
{
struct container* result = NULL;
struct container* temp = list;
while (temp != NULL) {
struct dog* tempDog = (struct dog*) malloc(sizeof(struct dog));
tempDog = temp->dog;
if (strcmp(temp->dog->breed, breed) == 0) {
struct container *cont_add = (struct container*) malloc(sizeof(struct container));
struct dog *dog_add = (struct dog*) malloc(sizeof(struct dog));
strcpy(dog_add->name, temp->dog->name);
strcpy(dog_add->breed, breed);
dog_add->checkups = temp->dog->checkups;
cont_add->dog = dog_add;
if (result == NULL) {
result = cont_add;
}
else {
struct container* temp2 = result;
while (temp2->next != NULL) {
temp2 = temp2->next;
}
temp2->next = cont_add;
}
}
temp = temp->next;
}
return result;
}
I noticed the following problems. You have couple of uninitialized members, and you use them. As a consequence, your program has undefined behavior.
First One
In add_doc, you are not initializing the member checkupsof the newly malloc'edstruct dog`. Add
tempDog->checkups = NULL;
after the line
strcpy(tempDog->breed, breed);
Second One
In list_of_breed, you are not setting the next member of cont_dog before using it.
Add the line
cont_add->next = NULL;
after
cont_add->dog = dog_add;
Future Problem
In list_of_breed, you have the line:
dog_add->checkups = temp->dog->checkups;
That makes a shallow copy of checkups. In order to avoid freeing checkups more than once, you will need to make deep copies of checkups.
#include <stdio.h>
#include <stdlib.h>
typedef struct nodeNum
{
int num;
struct nodeNum *next;
} t_nodeNum;
// Functions declaration ----------------------------
int menu(); // display menu and return choice
t_nodeNum* addition(t_nodeNum *node, int n);
void print_list(t_nodeNum *node);
// ----------------------------------------------------
// Main program to test link list functions
int main()
{
int choice;
t_nodeNum *pnode = NULL;
t_nodeNum *head = NULL;
t_nodeNum *temp = NULL;
int numAdd = 0;
int len = 0;
int first = 1;
do
{
choice = menu();
switch (choice)
{
case 1:
{
printf("Please enter number : \n");
scanf("%d", &numAdd);
if (first)
{
pnode = (t_nodeNum *)malloc(sizeof(t_nodeNum));
if (pnode == NULL)
{
printf("\n Error in allocation\n");
exit(0);
}
pnode->num = numAdd;
pnode->next = NULL;
first = 0;
head = pnode;
}
pnode = addition(pnode, numAdd);
break;
}
case 4:
{
printf("\n Print List: ");
print_list(head);
break;
}
}
}
while (choice != 5);
return 0;
}
// function menu display menu and return choice
int menu()
{
int choice = 0;
do
{
printf("Please choose option to do: \n");
printf("1. addition\n");
printf("2. deletion\n");
printf("3. search\n");
printf("4. print\n");
printf("5. exit\n");
printf("\n option = ");
scanf("%d", &choice);
}
while (choice < 1 || choice > 5);
return choice;
}
// function addition to add item to linked list in recursion
t_nodeNum* addition(t_nodeNum *p, int numAdd)
{
int len = 0;
if (p == NULL)
{
p = (t_nodeNum *)malloc(sizeof(t_nodeNum));
if (p == NULL)
{
printf("\n Error in allocation\n");
exit(0);
}
p->num = numAdd;
p->next = NULL;
}
else
{
p = addition(p->next, numAdd);
}
return (p);
}
// function print_list to print linked list in recursion
void print_list(t_nodeNum *head)
{
printf("%d ", head->num);
if (head->next == NULL)
{
printf("\n");
return;
}
print_list(head->next);
}
There is problem with the addition function it does not work correctly to add new item to the linked list and I does not know what is wrong please help
After adding new items and do print list it display only the first item
In you main function -
pnode = addition(pnode, numAdd);
instead of pnode you need to pass pnode->next -
pnode = addition(pnode->next, numAdd);
Problem with first call is that pnode is not NULL so it just adds new element at head position replacing previous value and returns.
Therefore, new node is not being created.
I'm reading in from a text file likewise:
George Washington, 2345678
John Adams, 3456789
Thomas Jefferson, 4567890
James Madison, 0987654
James Monroe, 9876543
John Quincy Adams, 8765432
Andrew Jackson, 7654321
Martin Van Buren, 6543210
William Henry Harrison, 5432109
John Tyler, 4321098
The function to delete the name works, however when it is successful the printf statements just continue to loop in the command window. I tried using a break statement at the end of the loop, however that only led to saying that the name wasn't found. Can someone offer any insight?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//Creates node for holding student's information
struct node
{
char name [50];
int id;
struct node *next;
}*head;
//Create Function Prototypes
void readDataFile ();
void insert(char *inName, char *inID);
void display(struct node *d);
int deleteID(int num);
void deleteName(char *delete_name);
//Main function
int main()
{
//Declare variables
int i, num, delete_id, id;
char *name;
char nameDelete [50];
char nameInsert [50];
struct node *n;
//initialize link list
head = NULL;
//Read in file
readDataFile();
//Create list of operations utilized in program
while (1)
{
printf("\nList Operations\n");
printf("===============\n");
printf("1.Insert\n");
printf("2.Display\n");
printf("3.Delete by ID\n");
printf("4.Delete by Name\n");
printf("5.Exit\n");
printf("Enter your choice : ");
if(scanf("%d", &i) <= 0)
{
printf("Enter only an Integer\n");
exit(0);
}
else
{
switch(i)
{
case 1:
getchar();
printf("Enter the name to insert:");
scanf("%[^\n]s", nameInsert);
printf("\nEnter the ID associated with the name: ");
scanf("%d", &id);
break;
case 2:
if (head == NULL)
printf("List is Empty\n");
else
{
printf("Elements in the list are:\n");
}
display(n);
break;
case 3:
if(head == NULL)
printf("List is Empty\n");
else
{
printf("Enter the ID number to delete: ");
scanf("%d", &delete_id);
}
if(deleteID(delete_id))
printf("%d deleted successfully \n", delete_id);
else
printf("%d not found in the list\n", delete_id);
break;
case 4:
getchar();
if(head == NULL)
printf("List is Empty\n");
else
{
printf("Enter name to delete: ");
scanf("%[^\n]s", nameDelete);
printf("Checking for name %s...\n", nameDelete);
printf("%s not found in the list\n", nameDelete);
deleteName(nameDelete);
}
break;
case 5:
return 0;
default:
printf("Invalid option\n");
}
}
}
return 0;
}
//Define the functions
//Function to delete by name
void deleteName(char *delete_name)
{
//Create temporary and helper node
struct node *temp, *helper;
//Set temp equal to head
temp = head;
//Loop until the end of the list
while(temp != NULL)
{
if(strcmp(temp->name, delete_name) == 0)
{
if(temp == head)
{
head = temp->next;
free(temp);
printf("Found %s!\n", delete_name);
printf("%s deleted successfully\n", delete_name);
}
else
{
helper->next = temp->next;
free(temp);
printf("Found %s!\n", delete_name);
printf("%s deleted successfully\n", delete_name);
}
}
else
{
helper = temp;
temp = temp->next;
}
}
break;
}
Please learn how to make an MCVE (How to create a Minimal, Complete, and Verifiable Example?) or SSCCE (Short, Self-Contained, Correct Example) — two names and links for the same basic idea.
Here's an MCVE derived from your code. I added the missing break; or return; from the loop in deleteName(). I rewrote main() essentially completely, but it works cleanly:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char name[50];
int id;
struct node *next;
} *head;
void deleteName(char *delete_name);
int main(void)
{
struct node *n;
head = NULL;
head = malloc(sizeof(*head));
assert(head != 0);
strcpy(head->name, "Abraham Lincoln");
head->id = 1;
head->next = 0;
n = malloc(sizeof(*n));
strcpy(n->name, "George Washington");
n->id = 2;
n->next = head;
head = n;
n = malloc(sizeof(*n));
strcpy(n->name, "John Adams");
n->id = 3;
n->next = head;
head = n;
deleteName("George Washington");
deleteName("John Adams");
deleteName("Abraham Lincoln");
return 0;
}
void deleteName(char *delete_name)
{
struct node *temp, *helper = 0;
temp = head;
while (temp != NULL)
{
if (strcmp(temp->name, delete_name) == 0)
{
if (temp == head)
{
head = temp->next;
free(temp);
printf("Found %s!\n", delete_name);
printf("%s deleted successfully\n", delete_name);
}
else
{
helper->next = temp->next;
free(temp);
printf("Found %s!\n", delete_name);
printf("%s deleted successfully\n", delete_name);
}
return; // The key change!
}
else
{
helper = temp;
temp = temp->next;
}
}
}
This ran cleanly under valgrind and Mac OS X 10.10.2 with GCC 4.9.1.
Found George Washington!
George Washington deleted successfully
Found John Adams!
John Adams deleted successfully
Found Abraham Lincoln!
Abraham Lincoln deleted successfully
It is important to learn how to be brutal about stripping out irrelevant code when creating an MCVE.
The break keyword will break out of the nearest switch or loop. Therefore, you can try this:
while(temp != NULL)
{
if(strcmp(temp->name, delete_name) == 0)
{
if(temp == head)
{
head = temp->next;
free(temp);
printf("Found %s!\n", delete_name);
printf("%s deleted successfully\n", delete_name);
break;
}
else
{
helper->next = temp->next;
free(temp);
printf("Found %s!\n", delete_name);
printf("%s deleted successfully\n", delete_name);
break;
}
}
else
{
helper = temp;
temp = temp->next;
}
}
An alternate solution is to set temp to NULL after you free it (this is good practice anyway, so that might be another idea)
Add the return statement at the end of the if block once you have found the name to be deleted
void deleteName(char *delete_name)
{
//Create temporary and helper node
struct node *temp, *helper;
//Set temp equal to head
temp = head;
//Loop until the end of the list
while(temp != NULL)
{
if(strcmp(temp->name, delete_name) == 0)
{
if(temp == head)
{
head = temp->next;
free(temp);
printf("Found %s!\n", delete_name);
printf("%s deleted successfully\n", delete_name);
}
else
{
helper->next = temp->next;
free(temp);
printf("Found %s!\n", delete_name);
printf("%s deleted successfully\n", delete_name);
}
return;
}
else
{
helper = temp;
temp = temp->next;
}
}
}
Also you how are planning to indicate that the name isn't part of the list, as opposed to being found and deleted. You can change modify the function such that it returns an error code when it hasn't found the name in the list, which is then used to indicate the name was never in the list to begin with.
I did not really look at the delete() function,
however, the following code illustrates how the
code should be formatted, etc.
notice the checking for input errors, which should always be performed
notice the separation of the struct definition from the struct declaration
notice the easy readability of the switch cases
by incorporating some vertical white space
notice the simple comments after the closing braces
notice that no call to an action is performed if the linked list is empty
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//define node for holding student's information
struct node
{
char name [50];
int id;
struct node *next;
};
// create head pointer for linked list of student info
// and initialize
struct node *head = NULL;
// Function Prototypes
// note: if all these functions are only accessed within this file
// then they should be declared with the 'static' modifier
void readDataFile (void);
void insert (char *inName, char *inID);
void display (struct node *d);
void deleteID (int delete_ID);
void deleteName (char *delete_name);
//Main function
int main()
{
//Declare local variables
// notice use of meaningful names
// notice, for readability and documentation,
// only one variable declared per line
int i; // receives user menu selection input
int idDelete;
int idInsert;
char nameDelete [50];
char nameInsert [50];
// struct node *n; // unused variable
int done = 0; // used to exit when user enters '5'
//Read in file
readDataFile();
//Create list of operations utilized in program
while (!done)
{
printf("\nList Operations\n");
printf("===============\n");
printf("1.Insert\n");
printf("2.Display\n");
printf("3.Delete by ID\n");
printf("4.Delete by Name\n");
printf("5.Exit\n");
printf("Enter your choice : ");
if( 1 != scanf("%d", &i) )
{ // then, scanf failed
perror( "scanf for choice failed");
exit( EXIT_FAILURE );
}
// implied else, scanf successful
switch(i)
{
case 1:
int ch;
while(EOF != (ch = getchar()) && (ch != '\n'));
printf("Enter the name to insert:");
if( 1 != (scanf("%[^\n]s", nameInsert) ) )
{ // then scanf failed
perror( "scanf for new student name failed");
exit( EXIT_FAILURE );
}
// implied else, scanf successful
printf("\nEnter the ID associated with the name: ");
if( 1 != (scanf("%d", &idInsert) ) )
{ // then scanf failed
perror( "scanf for new student ID failed");
exit( EXIT_FAILURE );
}
// implied else, scanf successful
insert( nameInsert, idInsert );
break;
case 2:
if (head == NULL)
printf("List is Empty\n");
else
{
printf("Elements in the list are:\n");
display(n);
} // end if
break;
case 3:
if(head == NULL)
printf("List is Empty\n");
else
{
printf("Enter the ID number to delete: ");
if( 1 != (scanf("%d", &idDelete) ) )
{ // then, scanf failed
perror( "scanf for ID to delete failed");
exit( EXIT_FAILURE );
}
// implied else, scanf successful
deleteID(idDelete);
} // end if
break;
case 4:
int ch;
while(EOF != (ch = getchar()) && (ch != '\n'));
if(head == NULL)
printf("List is Empty\n");
else
{
printf("Enter name to delete: ");
if( 1 != (scanf("%[^\n]s", nameDelete) ) )
{ // then, scanf failed
perror( "scanf for name to delete failed");
exit( EXIT_FAILURE );
}
// implied else, scanf successful
printf("Checking for name %s...\n", nameDelete);
deleteName(nameDelete);
} // end if
break;
case 5:
done = 1; // this will cause while() loop to exit
break;
default:
printf("Invalid option\n");
break;
} // end switch
} // end while
return 0;
} // end of function: main