I added a "search" function for my linked list menu and I don't know what is wrong in my code. When I enter a search key which is a name that is not in the list, instead of printing the "Search Key: %s Not Found!", the program will just stop. How to fix it? Any suggestion on how can I improve my program?
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
struct list
{
char name[20];
int age;
char gender[10];
struct list *next;
};
void main(void)
{
struct list *HEAD = NULL;
struct list *temp,*current, *trav;
struct list *prev,*temp1,*temp2;
char choice;
while(1)
{
clrscr();
printf("MENU\n");
printf("A) ADD\n");
printf("B) DISPLAY\n");
printf("C) DELETE\n");
printf("D) SEARCH\n");
printf("X) EXIT\n");
scanf("%c", &choice);
switch(toupper(choice))
{
case 'A':
temp= (struct list*)malloc(sizeof(struct list));
temp->next=NULL;
printf("Fill-Up the following:\n");
printf("Name:");
fflush(stdin);
gets(temp->name);
printf("Age:");
fflush(stdin);
scanf("%d",&temp->age);
printf("Gender:");
fflush(stdin);
gets(temp->gender);
if(HEAD == NULL)
{
HEAD = temp;
}
else if(HEAD!=NULL)
{
for(trav=HEAD; trav->next != NULL; trav= trav->next);
trav->next=temp;
}
else
{
printf("Not Enough Memory!\n");
}
break;
case 'B':
if(HEAD==NULL)
{
printf("Linked List is Empty!\n");
getch();
}
else{
for(trav=HEAD; trav != NULL; trav=trav->next )
{
printf("\nName: %s\n", trav->name);
printf("Age: %d\n", trav->age);
printf("Gender: %s\n\n", trav->gender);
}
getch();
}
break;
case 'C' :
temp1=( struct list*)malloc(sizeof(struct list));
temp1->next=NULL;
if(HEAD==NULL)
{
printf("No item to be delete. List is Empty!\n");
getch();
}
else {
printf("Enter The Name of the item you want to Delete: ");
fflush(stdin);
gets(temp1->name);
current=HEAD;
if(strcmp(temp1->name,current->name)== 0)
{
HEAD=HEAD->next;
free(current);
printf("Item has been successfully deleted from the list.\n");
getch();
}
else
{
for(prev=HEAD,trav=HEAD->next; strcmp(trav->name,temp1->name) == 1 ; trav=trav->next,prev=prev->next);
if(trav==NULL)
{
printf("Name: %s not found!", temp1->name);
getch();
}
else{
prev->next=trav->next;
free(trav);
printf("Item has been successfully deleted from the list.\n");
getch();
}
}
}
break;
case 'D':
temp2=( struct list*)malloc(sizeof(struct list));
temp2->next=NULL;
if(HEAD==NULL)
{
printf("No item to search. List is Empty.\n");
getch();
}
else{
printf("Enter Name (Search Key): ");
fflush(stdin);
gets(temp2->name);
int count=0;
struct list *trav2=HEAD;
while( trav2 !=NULL)
{
for(struct list *trav1=trav2; strcmp(trav1->name,temp2->name)!=0;trav1=trav1->next);
if(trav1!=NULL)
{
printf("\nName: %s\n", trav1->name);
printf("Age: %d\n", trav1->age);
printf("Gender: %s\n",trav1->gender);
trav2=trav1->next;
count++;
}
else {
trav2=NULL;
}
}
getch();
if(count==0)
{
printf("Search Key: %s Not Found!\n", temp2->name);
getch();
}
}
break;
case 'X':
if(HEAD!=NULL){free(HEAD); }
if(trav!=NULL){ free(trav); }
if(trav1!=NULL){ free(trav1); }
if(trav2!=NULL){ free(trav2); }
if(temp!=NULL){ free(temp); }
if(temp1!=NULL){ free(temp1); }
exit(1);
break;
}
}
}
In your search routine..
for(struct list *trav1=trav2; strcmp(trav1->name,temp2->name)!=0;trav1=trav1->next);
here trav1 will be null at the end of list but you are still going ahead and derefrencing it.
Add a check temp1 in your for loop like this:
for(struct list *trav1=trav2; trav1 && (strcmp(trav1->name,temp2->name)!=0);trav1=trav1->next);
Or, for better readability:
for (struct list *trav1 = trav2; trav1 != NULL; trav1 = trav1->next)
{
if (strcmp(trav1->name, temp2->name) !=0 )
break;
}
A few other comments on your code:
Do not use fflush(stdin) use something like this since that is not guaranteed by the standard to work.
int c;
while ((c = getchar()) != EOF && c != '\n')
;
Stop using gets(). It is impossible to use gets() safely. Use fgets() instead (but be aware it keeps the newline where gets() discards it).
Your loop continues while while( trav2 !=NULL). But where do you set trav2 = trav2->next? Without that, you loop will just continue forever.
But your code seems to have more problems than just that. Why are you allocating a new list item? Just declare a pointer to a list item (struct list*) and then point it to the head of your list.
for (temp = HEAD; temp != NULL; temp = temp->next)
{
// Examine temp for the value you are looking for
}
I suspect you are still new to understanding pointers. That is key to getting this code working right.
Related
I have this program that does not throw error, but the viewl procedure only shows the first item in the list. How do I for the viewl procedure that printing but in the reverse order to what does the procedure viewr?
#include <stdio.h>
#include <conio.h>
#include <windows.h>
#include <stdlib.h>
struct list
{
int info;
struct list *nxt,*prv;
}*HEAD=NULL,*AUX=NULL,*P=NULL,*F=NULL,*QD=NULL,*FD=NULL;
main function (ok)
int main()
{
void insertr(void);
void extractr(void);
void viewr(void);
void viewl(void);
void deleten();
void deletep();
char opc;
do
{
system("cls");
printf("___________________________________________________\n");
printf("_______¡¡¡DOUBLE-LINKED CIRCULAR LIST MENU!!!______\n");
printf("___________________________________________________\n");
printf("_________________SELECT AN OPTION__________________\n");
printf("___________________________________________________\n");
printf("___________________________________________________\n");
printf("__________1) INSERT________________________________\n");
printf("__________2) VIEW ASCENDING________________________\n");
printf("__________3) VIEW DESCENDING_______________________\n");
printf("__________4) ENTERING AND ELIMINATE NEXT___________\n");
printf("__________5) ENTERING AND ELIMINATE PREVIOUS_______\n");
printf("__________6) EXIT__________________________________\n");
printf("___________________________________________________\n");
opc=getch();
switch(opc)
{
case '1':
insertr();
break;
case '2':
viewr();
break;
case '3':
viewl();
break;
case '4':
deleten();
break;
case '5':
deletep();
break;
}
}
while(opc!='6');
getch();
return 0;
}
insert right process
void insertr(void)
{
P=HEAD;/* very first execution of this method P=NULL */
AUX=(struct list *)malloc(sizeof(struct list));
system("cls");
printf("ENTER AN ENTIRE NUMBER: ");
scanf("%d",&AUX->info);
AUX->nxt=HEAD;
AUX->prv=HEAD;
F=AUX;
if(HEAD==NULL)
{
HEAD=AUX;
P = AUX;/*first execution of this method P is no longer NULL but P is pointing to AUX */
}
else
{
while (P->nxt!=HEAD)
{
P=P->nxt;
}
}
P->nxt=AUX;
AUX->prv=P;
HEAD->prv=AUX;
}
void deleten()
{
int x;
system("cls");
printf("ENTER A NUMBER TO ELIMINATE THE FOLLOWING: ");
scanf("%d",&x);
FD=HEAD;
QD=HEAD;
while(FD->info!=x&&FD->nxt!=HEAD)
{
FD=FD->nxt;
}
QD=FD->nxt;
if(FD->nxt==HEAD&&FD->info!=x)
{
printf("\nENTERED NUMBER IS NOT LISTED");
}
else
{
if(FD->info==x)
{
FD->nxt=QD->nxt;
(QD->nxt)->prv=FD;
printf("\nDELETED %d",QD->info);
free(QD);
}
}
getch();
}
deletea process (ok)
void deletep()
{
int x;
system("cls");
printf("ENTER A NUMBER TO REMOVE THE PREVIOUS ");
scanf("%d",&x);
FD=HEAD;
QD=HEAD;
while (FD->info!=x&&FD->nxt!=HEAD)
{
FD=FD->nxt;
}
QD=FD->prv;
if(FD->nxt==HEAD&&FD->info!=x)
{
printf("\nENTERED NUMBER IS NOT LISTED");
}
else
{
if(FD->info==x)
{
FD->prv=QD->prv;
(QD->prv)->nxt=FD;
printf("\nDELETED %d",QD->info);
free(QD);
}
}
getch();
}
viewr process (ok):
void viewr(void)
{
system("cls");
if(HEAD==NULL)
{
printf("EMPTY LIST");
getchar();
return;
}
AUX=HEAD;
printf("LIST:\n\n");
while(AUX->nxt!=HEAD)
{
printf("-> %d\n",AUX->info);
AUX=AUX->nxt;
}
if(AUX->nxt==HEAD)
{
printf("-> %d\n",AUX->info);
}
getch();
}
this function fails:
void viewl(void)
{
system("cls");
if(HEAD==NULL)
{
printf("EMPTY LIST");
getchar();
return;
}
AUX=F;
printf("LIST:\n\n");
do
{
printf("-> %d\n",AUX->info);
AUX=AUX->prv;
}
while(AUX->nxt!=HEAD);
getch();
}
The code had several logical errors, other variables, etc. Here it is working without problems
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<windows.h>
//THIS IS TO CREATE THE LIST
struct list{
int info;
struct list *nxt,*prv;
}*HEAD=NULL,*AUX=NULL,*P=NULL,*FD=NULL,*QD=NULL,*Fd=NULL,*Qd=NULL;
int main(){
void insertr(void);
void viewr(void);
void viewl(void);
void deleten();
void deletep();
char opt;
do{
system("cls");
printf("___________________________________________________\n");
printf("_______¡¡¡DOUBLE-LINKED CIRCULAR LIST MENU!!!______\n");
printf("___________________________________________________\n");
printf("_________________SELECT AN OPTION__________________\n");
printf("___________________________________________________\n");
printf("___________________________________________________\n");
printf("__________1) INSERT________________________________\n");
printf("__________2) VIEW ASCENDING________________________\n");
printf("__________3) VIEW DESCENDING_______________________\n");
printf("__________4) ENTERING AND ELIMINATE NEXT___________\n");
printf("__________5) ENTERING AND ELIMINATE PREVIOUS_______\n");
printf("__________6) EXIT__________________________________\n");
printf("___________________________________________________\n");
opt=getch();
switch(opt) {
case '1':
insertr();
break;
case '2':
viewr();
break;
case '3':
viewl();
break;
case '4':
deleten();
break;
case'5':
deletep();
break;
}
}while(opt!='6');
return 0;
}
void insertr(void){
P=HEAD; /* very first execution of this method P=NULL */
AUX=(struct list *)malloc(sizeof(struct list));
system("cls");
printf("ENTER AN ENTIRE NUMBER: ");
scanf("%d",&AUX->info);
AUX->nxt=HEAD;
AUX->prv=HEAD; // The pointer to the previous node is null (HEAD is null)
if(HEAD==NULL){ //I ask if HEAD is equal to Null
HEAD=AUX;
P=AUX; /* The first execution of this method P is no longer NULL but P is pointing to AUX */
}else{ //THIS YES
while(P->nxt!=HEAD){
P=P->nxt;
}
}
P->nxt=AUX; // The next pointer of P takes the value of AUX
AUX->prv=P;
HEAD->prv=AUX;
}
void deleten(){
int x;
system("cls");
printf("ENTER A NUMBER TO ELIMINATE THE FOLLOWING: ");
scanf("%d",&x);
FD=HEAD;
QD=HEAD;
while(FD->info!=x&&FD->nxt!=HEAD){ // if what I am going to eliminate is different from the number that was entered and if there is another
FD=FD->nxt; //step to the next node
}
QD=FD->nxt;
if(FD->nxt==HEAD&&FD->info==x){
printf("\nIT IS THE HEADBOARD! CAN NOT BE ELIMINATED");
}else
if(FD->nxt==HEAD&&FD->info!=x){
printf("\nTHE NUMBER ENTERED IS NOT IN THE LIST");
}else{
FD->nxt=QD->nxt;
(QD->nxt)->prv=FD;
printf("\nDELETED %d",QD->info);
free(QD); //free space in memory occupied by QD
}
getch();
}
void deletep()
{
int xd;
system("cls");
printf("IENTER A NUMBER TO REMOVE THE PREVIOUS: ");
scanf("%d",&xd);
Fd=HEAD;
Qd=HEAD;
while(Fd->info!=xd){
Fd=Fd->prv;
} Qd=Fd->prv;
if(Fd==HEAD){
printf("\nIT'S THE HEAD! CAN NOT BE ELIMINATED");
}else{
if(Qd==HEAD){
HEAD=HEAD->nxt;
Fd->prv=Qd->prv;
(Fd->prv)->nxt=Fd;
printf("\nDELETED %d",Qd->info);
}else{
Fd->prv=Qd->prv;
(Qd->prv)->nxt=Fd;
printf("\nDELETED %d",Qd->info);
}
free(Qd);
}
getch();
}
void viewr(void)
{
system("cls");
if(HEAD==NULL){
printf("LISTA VACIA");
getchar();
return;
}
AUX=HEAD;
printf("LISTA:\n\n");
while(AUX->nxt!=HEAD){
printf("->%d\n",AUX->info);
AUX=AUX->nxt;
}
if(AUX->nxt==HEAD){
printf("->%d\n",AUX->info);
}
getch();
}
void viewl(void){
system("cls");
if(HEAD==NULL){
printf("EMPTY LIST");
getchar();
return;
} AUX=HEAD->prv;
printf("LIST:\n\n");
do{
printf("->%d\n",AUX->info);
AUX=AUX->prv;
}while(AUX->nxt!=HEAD);
getch();
}
in your code:
do
{
printf("-> %d\n",AUX->info);
AUX=AUX->prv;
}
while(AUX->nxt!=HEAD);
It can be happening something like this.
As you are going to the previous node and checking if next is head, next will be head if you built your list to be double-linked and circular.
try like this:
do
{
AUX=AUX->prv;
printf("-> %d\n",AUX->info);
}
while(AUX!=HEAD);
and you should avoid using all variables as global.
So this program is supposed to create a linked list for a car with the information of the year, Safety Rating, and Model. However when outputting the safety rating, say if the user enters "5", the program outputs it as some very large number that isn't what the user entered.
Example: If the user enters
Enter Year for Car: 1992
Enter Rating for Car (0.00 - 100.00): 25.5
Enter Model for Car: Chevy
The program output is...
The Cars in the List Are As Follows:
Year:1992 Rating:79960111893652368676401906121179136.00 Model:Chevy
When it should be....
The Cars in the List Are As Follows:
Year:1992 Rating:25.50 Model:Chevy
What am I doing wrong? Here is my full code...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSIZE 400
struct car {
int year;
float safeRating;
char model[MAXSIZE];
struct car *next;
};
typedef struct car Car;
typedef struct car *CarPtr;
void menu();
void printList(CarPtr);
CarPtr makeCar(int, float, char *);
CarPtr removeCar(CarPtr, int);
CarPtr addCar(CarPtr sPtr, int infoA, float infoB, char *infoC);
void viewCar(CarPtr sPtr, int infoA, float infoB, char *infoC);
int main()
{
CarPtr startPtr;
int infoA, choice;
float infoB;
char infoC;
startPtr = NULL;
menu();
scanf("%d", &choice);
while (choice != 5){
switch (choice){
case 1: printf("\nEnter Year for Car: ");
scanf("%d", &infoA);
printf("\nEnter Rating for Car (0.00 - 100.00): ");
scanf("%f", &infoB);
printf("\nEnter Model for Car: ");
scanf("%s", &infoC);
startPtr = addCar(startPtr, infoA, infoB, &infoC);
printList(startPtr);
printf("\n");
break;
case 2: printf("\nEnter Car for deletion : ");
scanf("%d", &infoA);
startPtr = removeCar(startPtr, infoA);
printList(startPtr);
printf("\n");
break;
case 3: printf("\nEnter Car Number to View : ");
scanf("%d", &infoA);
viewCar(startPtr, infoA, infoB, &infoC);
printf("\n");
break;
case 4: printList(startPtr);
printf("\n");
break;
default: printf ("Invalid Option... Please Try Again \n");
break;
}
menu();
scanf("%d", &choice);
}
return 0;
}
void menu()
{
printf ("\t1: Insert Car into Ordered List\n");
printf ("\t2: Remove Car from List\n");
printf ("\t3: View Car from List\n");
printf ("\t4: Printing the List\n");
printf ("\t5: Exit\n");
printf ("\tEnter Choice: ");
}
CarPtr makeCar(int infoA, float infoB, char *infoC)
{
CarPtr np = (CarPtr) malloc(sizeof(Car));
np->year = infoA;
np->safeRating = infoB;
strcpy(np->model, infoC);
np->next = NULL;
return np;
}
void printList(CarPtr sPtr)
{
if(sPtr == NULL){
printf ("\nThere are no Cars to be Printed\n");
}
else {
printf("The Cars in the List Are As Follows Sorted by Year: \n");
while (sPtr != NULL) {
printf("Year:%d Rating:%.2f Model:%s\n", sPtr->year, sPtr->safeRating, sPtr->model);
sPtr = sPtr->next;
}
}
}
CarPtr addCar(CarPtr sPtr, int infoA, float infoB, char *infoC)
{
CarPtr newPtr, currPtr, prevPtr;
newPtr = makeCar(infoA, infoB, infoC);
prevPtr = NULL;
currPtr = sPtr;
while (currPtr != NULL && infoA > currPtr->year) {
prevPtr = currPtr;
currPtr = currPtr->next;
}
if (prevPtr == NULL) { // inserting at the start of the list
newPtr->next = sPtr;
sPtr = newPtr; // start of list has now changed
}
else {
newPtr->next = currPtr;
prevPtr->next = newPtr;
}
return sPtr;
}
CarPtr removeCar(CarPtr sPtr, int infoA)
{
CarPtr previousPtr, currentPtr, tempPtr;
previousPtr = NULL;
currentPtr = sPtr;
if(sPtr == NULL){
printf ("\nThe List is empty... No cars to be Removed\n");
return sPtr;
}
while (currentPtr != NULL && currentPtr->year != infoA) {
previousPtr = currentPtr;
currentPtr = currentPtr->next;
}
if(currentPtr == NULL){
printf("\nCar ( %d ) was not found \n", infoA);
}
else if (previousPtr == NULL){ // if node to be deleted is the first node
tempPtr = sPtr;
sPtr = sPtr->next; // start of list has been changed
printf("\nCar ( %d ) was deleted \n", tempPtr->year);
free(tempPtr);
}
else{
tempPtr = currentPtr;
previousPtr->next = currentPtr->next;
printf("\nCar ( %d ) was deleted \n", tempPtr->year);
free(tempPtr);
}
return sPtr;
}
void viewCar(CarPtr sPtr, int infoA, float infoB, char *infoC)
{
CarPtr previousPtr, currentPtr;
previousPtr = NULL;
currentPtr = sPtr;
int position = 0;
if(sPtr == NULL){
printf ("\nThe List is empty... No cars to View\n");
return;
}
while (currentPtr != NULL && currentPtr->year != infoA) {
previousPtr = currentPtr;
currentPtr = currentPtr->next;
position++;
}
if(currentPtr == NULL){
printf("\nCar ( %d ) was not found \n", infoA);
}
else{
printf("\nCar ( %d ) Rating: %.2f Model: %s was found at position : %d\n", currentPtr->year, currentPtr->safeRating, currentPtr->model, (position + 1));
}
}
You're not allocating any space for the car model string. You're scanf("%s", &infoC);, but infoC is a single char, there's no space for a string. That's overwriting something and probably mucking with things. Then you go strcpy when you make your car, that will copy until it hits a NULL byte. ,, etc, etc, ,, UB. Best to define it as char infoC[MAXSIZE] to match what you have in struct car.
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
I opened a thread yesterday asking about how I should proceed. Here is what I've got so far (sorry for the language, the program will be in Albanian but I'm sure you are getting the point).
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
void regjistrim();
void kerkim();
void modifikim();
void fshirje();
void rradhitje();
void display();
void load();
#define EMRI 50
#define MBIEMRI 50
#define ID 20
#define TEL 20
#define EMAIL 25
typedef struct node
{
char emri[EMRI];
char mbiemri[MBIEMRI];
char id[ID];
char tel[TEL];
char email[EMAIL];
struct node* next;
} node;
FILE* addressbook;
node* mynode;
node* curr;
int main(void)
{
char input[2];
int choice;
load();
printf("----------------ADDRESS BOOK----------------");
printf("\n\n\t1 - Regjistrimi i ri\n");
printf("\n\t2 - Kerkim\n");
printf("\n\t3 - Modifikim\n");
printf("\n\t4 - Fshirje\n");
printf("\n\t5 - Rradhitje\n");
printf("\n\t6 - Afishim i address book\n");
printf("\n\t0 - Exit\n");
fgets(input, 4, stdin);
sscanf(input, "%d", &choice);
while (choice < 0 || choice > 6)
{
printf("\nShtypni nje numer nga 0 - 6: \n");
fgets(input, 4, stdin);
sscanf(input, "%d", &choice);
}
switch (choice)
{
case 1:
regjistrim();
break;
case 2:
kerkim();
break;
case 3:
modifikim();
break;
case 4:
fshirje();
break;
case 5:
rradhitje();
break;
case 6:
display();
break;
case 0:
exit(0);
break;
}
return 0;
}
void load()
{
addressbook = fopen("Addressbook.txt", "r");
if (addressbook == NULL)
printf("Could not open file.");
node* mynode = malloc(sizeof(node));
while (fscanf(addressbook, "%s %s %s %s %s", mynode->emri, mynode->mbiemri, mynode->id, mynode->tel, mynode->email) != EOF)
{
node* mynode = malloc(sizeof(node));
mynode = mynode->next;
}
mynode = curr;
}
//Regjistron nje qytetar ne addressbook
void regjistrim()
{
char input[2];
char answer;
do
{
node* newnode = malloc(sizeof(node));
curr->next = newnode;
addressbook = fopen("Addressbook.txt", "a+");
printf("\nShtypni emrin: ");
fgets(newnode->emri, EMRI, stdin);
printf("\nShtypni mbiemrin: ");
fgets(newnode->mbiemri, MBIEMRI, stdin);
printf("\nShtypni ID-in: ");
fgets(newnode->id, ID, stdin);
printf("\nShtypni nr. telefoni: ");
fgets(newnode->tel, TEL, stdin);
printf("\nShtypni email-in: ");
fgets(newnode->email, EMAIL, stdin);
fprintf(addressbook, "Emri: %sMbiemri: %sID: %sNr. telefoni: %sEmail: %s\n", newnode->emri, newnode->mbiemri, newnode->id, newnode->tel, newnode->email);
fclose(addressbook);
printf("\nShtypni y/Y neqoftese doni te regjistroni person tjeter: ");
fgets(input, 50, stdin);
sscanf(input, "%c", &answer);
curr = newnode;
}
while(answer == 'y' || answer == 'Y');
}
void kerkim()
{
//TODO
}
void modifikim()
{
//TODO
}
void fshirje()
{
//TODO
}
void rradhitje()
{
//TODO
}
void display()
{
//TODO
}
Currently I'm getting a segfault at this point: while (fscanf(addressbook, "%s %s %s %s %s", mynode->emri, mynode->mbiemri, mynode->id, mynode->tel, mynode->email) != EOF)
I am mainly concerned about the load() function which will load any entries to the linked list, if there are any, before the user does any action.
Thank you in advance.
I recommend you check out existing implementations of linked lists. Add helper functions for inserting nodes, appending nodes, deleting nodes, and those sorts of things. Once you have a working implementation for the lists themselves, you will have an easier time writing code that takes advantage of the linked list data structure.
Consider changing your node structure to include a pointer to the actual data and a pointer to the next node (instead of actually having the data in the struct itself). Better practice this way. You could even expand your linked list implementation to support any data type by using void pointers as "generic" pointers.
A segmentation fault with linked lists usually indicates that you are dereferencing a NULL pointer somewhere in your code (but is not the case all of the time!). Ensure that you are not referencing nodes that have been deleted or nodes that have not been allocated yet.
If you are satisfied with your current implementation, step through the code with gdb and set a breakpoint where the program is segfaulting. You should not have a hard time tracking down where the bug is.
If you want to create a linked list try doing this
Replace this code
node* mynode = malloc(sizeof(node));
while (fscanf(addressbook, "%s %s %s %s %s", mynode->emri, mynode->mbiemri, mynode->id, mynode->tel, mynode->email) == 5)
{
node* mynode = malloc(sizeof(node));
mynode = mynode->next;
}
mynode = curr;
with this
node* mynodeLocal = malloc(sizeof(node));
node *secondLastNode;
while (fscanf(addressbook, "%s %s %s %s %s", mynodeLocal->emri, mynodeLocal->mbiemri, mynodeLocal->id, mynodeLocal->tel, mynodeLocal->email) != EOF)
{
secondLastNode = mynodeLocal;
mynodeLocal->next = malloc(sizeof(node));
mynodeLocal = mynodeLocal->next;
mynodeLocal->next = NULL;
}
secondeLastNode->next = NULL;
mynode = curr;//Change this line according to your requirement.
The problem was solved. A guy gave it in comments. The problem was that I was using %d to read in a short int. I should have used %hd or I should have used an `int'.
I tried to create a program of singly-linked list using only local variables. I was able to make a working program by using global variables.
The program with local variables compiles but it crashes when I try to traverse the linked list.
I have absolutely no idea what is wrong with the implementation with local variables. What is the problem present in the Implementation with local variables?
ABOUT THE STRUCTURE OF THE PROGRAMS:
I understand that the programs are big so I'll put in something about structure of the program.
The program is structured as a menu driven program. So the initial calls to functions are in main() function
There are 3 options in main() menu - exit, traverse and insertion
Exit returns 0 to exit program while other 2 do function calls
Insertion function itself is arranged as menu-driven program.
It has 3 options - return , insert_begin and insert_end. The last 2 are function calls.
I know there are memory leaks as I haven't freed any memory but I will take care of that after I can understand the problem in the current program.
//WORKING IMPLEMENTATION USING GLOBAL VARIABLE
#include<stdio.h>
#include<stdlib.h>
#define MIN 0
#define MAX 2
#define INS_MIN 0
#define INS_MAX 2
typedef struct node
{
int data;
struct node *next;
}sll_node;
sll_node *start = NULL;
void intro()
{
system("cls");
printf("\n\tThese are the various options:\n");
printf("\n\t00 Exit");
printf("\n\t01 Traverse the list");
printf("\n\t02 Insertion into the list");
}
void insert_begin()
{
sll_node *node = malloc(sizeof(sll_node));
if(node == NULL)
{
printf("\n\tNot enough menory");
exit(-1);
}
int data;
printf("\n\tData to be entered: ");
scanf("%d", &data);
node->data = data;
node-> next = start;
start = node;
}
void insert_end()
{
sll_node *node = malloc(sizeof(sll_node));
if(node == NULL)
{
printf("\n\tNot enough menory");
exit(-2);
}
if(start == NULL)
insert_begin();
else
{
printf("\n\tData to be entered: ");
scanf("%d", &(node->data));
node-> next = NULL;
sll_node *node2;
for(node2 = start; node2->next != NULL; node2 = node2->next)
;
node2->next = node;
}
}
void insert_intro()
{
system("cls");
printf("\n\tThese are the various options:\n");
printf("\n\t00 Insertion Done");
printf("\n\t01 Insert at beginning");
printf("\n\t02 Insert at end");
}
void insertion()
{
short choice;
while(1)
{
choice = -1;
while(choice < INS_MIN || choice > INS_MAX)
{
insert_intro();
printf("\n\n\tEnter your chocie: ");
scanf("%d", &choice);
}
switch(choice)
{
case 0:
return;
case 1:
insert_begin();
break;
case 2:
insert_end();
break;
}
}
}
void traverse()
{
if(start == NULL)
printf("\n\n\tLinked list is empty");
else
{
printf("\n\n\t");
for(sll_node *node = start; node != NULL; node = node->next)
printf("%d ", node->data);
}
getch();
}
int main()
{
short choice;
while(1)
{
choice = -1;
while(choice < MIN || choice > MAX)
{
intro();
printf("\n\n\tEnter your choice: ");
scanf("%d", &choice);
}
switch(choice)
{
case 0:
return 0;
case 1:
traverse();
break;
case 2:
insertion();
break;
}
}
return 0;
}
//COMPILES BUT CRASHES - Same program but with local variable start and variable passing between functions
#include<stdio.h>
#include<stdlib.h>
#define MIN 0
#define MAX 2
#define INS_MIN 0
#define INS_MAX 2
typedef struct node
{
int data;
struct node *next;
}sll_node;
void intro()
{
system("cls");
printf("\n\tThese are the various options:\n");
printf("\n\t00 Exit");
printf("\n\t01 Traverse the list");
printf("\n\t02 Insertion into the list");
}
sll_node* insert_begin(sll_node *start)
{
sll_node *node = malloc(sizeof(sll_node));
if(node == NULL)
{
printf("\n\tNot enough menory");
exit(-1);
}
int data;
printf("\n\tData to be entered: ");
scanf("%d", &data);
node->data = data;
node-> next = start;
return node;
}
sll_node* insert_end(sll_node *start)
{
sll_node *node = malloc(sizeof(sll_node));
if(node == NULL)
{
printf("\n\tNot enough menory");
exit(-2);
}
if(start == NULL)
start = insert_begin(start);
else
{
printf("\n\tData to be entered: ");
scanf("%d", &(node->data));
node-> next = NULL;
sll_node *node2;
for(node2 = start; node2->next != NULL; node2 = node2->next)
;
node2->next = node;
}
return start;
}
void insert_intro()
{
system("cls");
printf("\n\tThese are the various options:\n");
printf("\n\t00 Insertion Done");
printf("\n\t01 Insert at beginning");
printf("\n\t02 Insert at end");
}
sll_node* insertion(sll_node *start)
{
short choice;
while(1)
{
choice = -1;
while(choice < INS_MIN || choice > INS_MAX)
{
insert_intro();
printf("\n\n\tEnter your chocie: ");
scanf("%d", &choice);
}
switch(choice)
{
case 0:
return start;
case 1:
start = insert_begin(start);
break;
case 2:
start = insert_end(start);
break;
}
}
}
void traverse(sll_node *start)
{
if(start == NULL)
printf("\n\n\tLinked list is empty");
else
{
printf("\n\n\t");
for(sll_node *node = start; node != NULL; node = node->next)
printf("%d ", node->data);
}
getch();
}
int main()
{
sll_node *start = NULL;
short choice;
while(1)
{
choice = -1;
while(choice < MIN || choice > MAX)
{
intro();
printf("\n\n\tEnter your choice: ");
scanf("%d", &choice);
}
switch(choice)
{
case 0:
return 0;
case 1:
traverse(start);
break;
case 2:
start = insertion(start);
break;
}
}
return 0;
}
You are not returning anything from insertion() function when item is added to a list. So linked list may not get constructed properly.
Probably, you should return start only when its added at the beginning, otherwise start in main() will not point to head of the list.
sll_node* insertion(sll_node *start)
{
...
switch(choice)
{
case 0:
return start;
case 1:
start = insert_begin(start);
return start; //<----- return node
break;
case 2:
start = insert_end(start);
break;
}
...
}
Change short choice to int choice.
Why does this make a difference?
Short answer is that printf("%d") expects an integer.
The long answer is "%d" describes the data type you are passing to printf as an integer (which is commonly 4 to 8 bytes), and you're giving it a datatype of short - which is commonly 2 bytes long. When your program reads the input and stores it at the pointer, &choice, it writes 4 bytes starting at that address (but only 2 were reserved). This causes a segmentation fault and will crash your program.
Here's a list to some printf documentation. You'll notice that to pass a short to printf you would write %hd instead of %d
When i compile your code on my computer, it works, but i changed "short choice" to "int choice", because scanf("%d", &choice) takes 4 bytes to write on, and when choice is short it crashes, because short has only 2 bytes, therefore stack corruption will occur, my be on your computer this corruption damage the "start" pointer.
About the crash. Change the argument start in both functions insert_begin and insert_end to sll_node ** start, and when assigning new value, use the expression *start = your-new-value. It is because you have to pass a pointer to the local variable start which is also pointer. You do not need to change function traverse.
About memory leaks, let me to point-out that when you call insert_begin from inside insert_end, the node created from insert_end is left unused. before exit() and the return in main() you should free the list.
Yes, sorry. There was another bug hard to see. It was at 2 lines where you read (choice).
short choice;
...
// It is ERROR to use "%d" with (short choice), because the stack will
// be overwritten with unsuspected results. The format specifier "%hd"
// say to compiler that (&choice) point to a short 16-bit integer,
// not 32-bit
scanf("%hd", &choice);
This is slightly different version, tested, without memory leaks.
//
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define MIN 0
#define MAX 2
#define INS_MIN 0
#define INS_MAX 2
typedef struct node
{
int data;
struct node *next;
} sll_node;
void clear_list(sll_node** start)
{
assert(start != NULL);
sll_node* node = *start;
while (node != NULL)
{
sll_node* element = node;
node = element->next;
free(element);
}
*start = NULL;
}
void intro()
{
system("cls");
printf("\n\tThese are the various options:\n");
printf("\n\t00 Exit");
printf("\n\t01 Traverse the list");
printf("\n\t02 Insertion into the list");
}
void insert_begin(sll_node** pstart)
{
sll_node* node = (sll_node*)malloc(sizeof(sll_node));
if (node == NULL)
{
printf("\n\tNot enough menory");
clear_list(pstart);
exit(-1);
}
int data;
printf("\n\tData to be entered: ");
scanf_s("%d", &data);//scanf
node->data = data;
node->next = *pstart;
// update the local variable start passed from main to point just inserted node
*pstart = node;
}
void insert_end(sll_node** start)
{
assert(start != NULL);
if (*start == NULL)
{
insert_begin(start);
}
else
{
sll_node* node = (sll_node*)malloc(sizeof(sll_node));
if (node == NULL)
{
printf("\n\tNot enough menory");
clear_list(start);
exit(-2);
}
printf("\n\tData to be entered: ");
scanf("%d", &(node->data));
node->next = NULL;
sll_node* node2;
for(node2 = *start; node2->next != NULL; node2 = node2->next)
;
node2->next = node;
}
}
void insert_intro()
{
system("cls");
printf("\n\tThese are the various options:\n");
printf("\n\t00 Insertion Done");
printf("\n\t01 Insert at beginning");
printf("\n\t02 Insert at end");
}
void insertion(sll_node** start)
{
short choice;
while(1)
{
choice = -1;
while(choice < INS_MIN || choice > INS_MAX)
{
insert_intro();
printf("\n\n\tEnter your chocie: ");
scanf("%hd", &choice);
}
switch(choice)
{
case 0:
return;
case 1:
insert_begin(start);
break;
case 2:
insert_end(start);
break;
}
}
}
void traverse(sll_node *start)
{
if (start == NULL)
printf("\n\n\tLinked list is empty");
else
{
printf("\n\n\t");
for(sll_node *node = start; node != NULL; node = node->next)
printf("%d ", node->data);
}
getch();
}
int main()
{
sll_node *start = NULL;
short choice;
while(1)
{
choice = -1;
while(choice < MIN || choice > MAX)
{
intro();
printf("\n\n\tEnter your choice: ");
scanf("%hd", &choice);
}
switch(choice)
{
case 0:
clear_list(&start);
return 0;
case 1:
traverse(start);
break;
case 2:
insertion(&start);
break;
}
}
return 0;
}
P.S. Very hard to edit! I'm new here and do not have enough experience. Wasted a lot of time to edit!