Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I am trying to append at the end of the list and return head at the end of this function.
This is a singly linked list. So, I have lost my head after traversing to the end.
file.c
#define NAME_LEN 30
struct equipment{
char type[NAME_LEN+1];
char description[NAME_LEN+1];
int quantity;
struct equipment *next;
};
struct equipment *append_to_list(struct equipment *list){
char type[NAME_LEN + 1], description[NAME_LEN + 1];
int quantity;
printf("Enter equipment type: ");
fgets(type, NAME_LEN, stdin);
printf("Enter description of the equipment: ");
fgets(description, NAME_LEN, stdin);
printf("Enter quantity: ");
scanf("%d", &quantity);
struct equipment *temp = (struct equipment *)malloc(sizeof(struct equipment));
strcpy(temp->type, type);
strcpy(temp->description, description);
temp->quantity = quantity;
temp->next = NULL;
bool doesExist = false;
if ( list == NULL ){
list = temp;
}
else{
while ( list->next != NULL ){
if ( list == temp ){
printf("This equipment is already in the list\n");
}
list = list->next;
}
list->next = temp;
}
// return head of this list here;
}
In this int main function, e_list should point to head of the linked list after calling append_to_list(e_list).
int main(void)
{
struct equipment *e_list = NULL;
e_list = append_to_list(e_list);
}
How do I create a reference and traverse that dummy head? That way I never lose my original head.
You need a temporary variable, in the else add
struct equipment *tmp;
tmp = list;
And replace all occurrences of list in the else. At the end return you list variable.
Since you are already putting the newly created structure temp at the end. Your head will not change between different calls in main because the head is at the opposite side of the end.
You need a static variable to keep track of head. Here is the tested code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define NAME_LEN 30
struct equipment
{
char type[NAME_LEN + 1];
char description[NAME_LEN + 1];
int quantity;
struct equipment *next;
};
struct equipment *
append_to_list (struct equipment *list)
{
char type[NAME_LEN + 1], description[NAME_LEN + 1];
int quantity;
printf ("Enter equipment type: ");
fgets (type, NAME_LEN, stdin);
printf ("Enter description of the equipment: ");
fgets (description, NAME_LEN, stdin);
printf ("Enter quantity: ");
scanf ("%d", &quantity);
struct equipment *temp =
(struct equipment *) malloc (sizeof (struct equipment));
strcpy (temp->type, type);
strcpy (temp->description, description);
temp->quantity = quantity;
temp->next = NULL;
bool doesExist = false;
static struct equipment * head = NULL; //New variable
if (list == NULL)
{
list = temp;
head = list;
}
else
{
while (list->next != NULL)
{
if (list == temp)
{
printf ("This equipment is already in the list\n");
}
list = list->next;
}
list->next = temp;
}
return head; //return head here
}
int main()
{
struct equipment *e_list = NULL;
e_list = append_to_list(e_list);
e_list = append_to_list(e_list);
e_list = append_to_list(e_list);
return 0;
}
You really could do a few things here.
Firstly though, your code is rather unsafe. Your buffers are far too small, don't use scanf to convert an integer (it doesn't check for failure), and don't use strcpy (especially when your buffers are tiny). Also, the calls to printf are a bit pointless if you're just using a literal string - puts() should be considered instead - and don't cast the return from malloc(). This is maybe a bit safer.
#include <bsd/bsd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#define NAME_LEN 32
#define nputs(STR) fputs((STR), stdout)
struct equipment {
char type[NAME_LEN];
char description[NAME_LEN];
int quantity;
struct equipment *next;
};
struct equipment *
append_to_list(struct equipment *list)
{
char type[BUFSIZ], description[BUFSIZ], quantity_string[BUFSIZ];
int quantity;
nputs("Enter equipment type: ");
fgets(type, BUFSIZ, stdin);
nputs("Enter description of the equipment: ");
fgets(description, BUFSIZ, stdin);
nputs("Enter quantity: ");
fgets(quantity_string, BUFSIZ, stdin);
char *endptr;
quantity = strtol(quantity_string, &endptr, 10);
if (quantity_string == endptr) {
fprintf(stderr, "Error: invalid integer input '%s'\n", quantity_string);
exit(1);
}
struct equipment *temp = malloc(sizeof *temp);
strlcpy(temp->type, type, NAME_LEN);
strlcpy(temp->description, description, NAME_LEN);
temp->quantity = quantity;
temp->next = NULL;
bool doesExist = false;
if (list == NULL) {
list = temp;
} else {
while (list->next != NULL) {
if (list == temp)
puts("This equipment is already in the list");
list = list->next;
}
list->next = temp;
}
// return head of this list here;
}
As to keeping track of the head, you could use a different function to initialize the tree than to append to it, thus giving you a slightly unique root object. You could add a field to each struct that stores the location of the root, or you could make a separate struct entirely that holds the root and perhaps some metadata about it. There are plenty of options. I agree with a few of the comments above, it isn't entirely clear what you're asking for here.
Related
This is my algorithm for adding nodes to a linked list which is in a sorted way for surnames of persons.
Here is the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Node {
char Name[1024];
char Surname[1024];
char Telno[1024];
struct Node* next;
};
void Add(struct Node** firstnode, struct Node* NewNode)
{
struct Node* tempo;
//printf("%d",strcmp((*firstnode)->Surname,NewNode->Surname));
if (*firstnode == NULL || (strcmp((*firstnode)->Surname,NewNode->Surname) > 0)) {
NewNode->next = *firstnode;
*firstnode = NewNode;
}
else {
tempo = *firstnode;
while (tempo->next != NULL && strcmp(tempo->Surname,NewNode->Surname) < 0) {
tempo = tempo->next;
}
NewNode->next = tempo->next;
tempo->next = NewNode;
}
}
struct Node* CreateNode(char name[1024], char surname[1024], char telno[1024])
{
struct Node* NewNode = (struct Node*)malloc(sizeof(struct Node));
strcpy(NewNode->Name,name);
strcpy(NewNode->Surname,surname);
strcpy(NewNode->Telno,telno);
NewNode->next = NULL;
return NewNode;
}
void Printlinkedlist(struct Node* head)
{
struct Node* temp = head;
while (temp != NULL) {
printf("%s %s %s\n", temp->Name,temp->Surname,temp->Telno);
temp = temp->next;
}
}
struct Node* head = NULL;
struct Node* temp;
int main()
{
int personcount;
char name[1024],surname[1024],telno[1024];
printf("Please give the count of person:");
scanf("%d", &personcount);
for (int i = 0; i < personcount; i++) {
printf("Please give the name of %d. person:", i + 1);
scanf(" %s", &name);
printf("Please give the surname of %d. person:", i + 1);
scanf(" %s", &surname);
printf("Please give the phone number of %d. person:", i + 1);
scanf(" %s", &telno);
temp = CreateNode(name,surname,telno);
Add(&head, temp);
}
printf("\n -------------- Linkedlist --------------\n");
Printlinkedlist(head);
return 0;
}
The first problem is this: For example, if I enter people's surnames as G, A, L, E, K (So first person's last name will be "G", second person's last name will be "A" etc..), it gives an incorrectly ordered output.
And the second one is: If I delete the comment line characters behind the printf inside the add function, I get a segmentation fault that I don't understand why
Thanks for the answer.
It should first be said that you could, and should, have figured it out yourself by either:
Debugging the program:
On Linux: How Can I debug a C program on Linux?
On Windows: How do you debug a C program on Windows?
Enabling core dumps and analyzing the core file you get when your program crashes; see this explanation.
But, more to the point, let's have a look at (some of) your code:
if (*firstnode == NULL || /* another condition */) {
// do stuff
}
else {
// so *firstnode may be NULL here
tempo = *firstnode;
while (tempo->next != /* some value */ && /* another condition*/ ) {
// do stuff
}
// do stuff
}
See the problem? tempo could get assigned a NULL point, and then de-referenced to get to the next field. That would likely cause a segmentation fault.
I am currently having trouble trying to print my doubly linked list out. The problem is either in the getSongInfo function or in the printSongInfo function. I am very new to coding and all the help is greatly appreciated. I also don't know how to use the tail pointer when using a doubly linked list.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<malloc.h>
#pragma warning(disable : 4996)
#pragma warning(disable : 6387)
#pragma once
//structs
typedef struct {
char* title;
char* artist;
int rating;
SongNode* next;
SongNode* prev;
}SongNode;
//Constants
#define kInfiniteLoop 1
#define kStringLength 30
//Prototypes
int getNum(void);
void eliminateEndOfLine(char* buffer);
void printSongInfo(SongNode* head);
SongNode* getSongInfo(SongNode** head, SongNode** tail, char title[], char artist[], int rating);
int main() {
char title[kStringLength];
char artist[kStringLength];
int rating = 0;
SongNode* head = NULL;
SongNode* tail = NULL;
printf("Enter Title, Artist and Rating\n");
printf("Enter'.' to get out of the loop and print list\n");
while (kInfiniteLoop) {
printf("Title: ");
fgets(title, kStringLength, stdin);
eliminateEndOfLine(title);
if (strcmp(title, ".") == 0) {
break;
}
printf("Artist: ");
fgets(artist, kStringLength, stdin);
eliminateEndOfLine(artist);
printf("Rating: ");
while (rating = getNum()) { // error check the rating this will check to make sure the rating is in the range 1-5.
if (rating < 1 || rating>5) {
printf("The number you have entered is invaild\n");
rating = 0;
printf("Rating: ");
continue;
}
break;
head=getSongInfo(&head, &tail, title, artist, rating);
printf("\n");
}
}
printSongInfo(head);
return 0;
}
/*===============================================================================================================*/
/*FUNCTION :getNum(void) */
/*PARAMETERS :void */
/*RETURNS :number */
/*DESCRIPTION:This function is the user input function to get a number rating */
/*===============================================================================================================*/
int getNum(void)
{/* the array is 121 bytes in size; we'll see in a later lecture how we can improve this code */
char record[121] = { 0 }; /* record stores the string */
int number = 0;
/* NOTE to student: indent and brace this function consistent with your others */
/* use fgets() to get a string from the keyboard */
fgets(record, 121, stdin);
/* extract the number from the string; sscanf() returns a number
* corresponding with the number of items it found in the string */
if (sscanf(record, "%d", &number) != 1)
{
/* if the user did not enter a number recognizable by
* the system, set number to -1 */
number = -1;
}
return number;
}
/*=======================================================================================================*/
/*FUCNTION :void eliminateEndOfLine */
/*PARAMETER :(char* buffer) */
/*RETURNS :void */
/*DESCRIPTION :This function takes a pointer to a string and looks through the string to find the */
/* newline.It takes the new line out of the string. */
/*=======================================================================================================*/
void eliminateEndOfLine(char* buffer)
{
char* target = strchr(buffer, '\n');
if (target != NULL)
{
*target = '\0';
}
}
SongNode* getSongInfo(SongNode** head, SongNode** tail, char title[], char artist[], int rating)
{
SongNode *newBlock = NULL;
newBlock = (SongNode*)malloc(sizeof(SongNode));
if (newBlock == NULL) {
printf("No memory to be Allocated\n");
return (*head);
}
newBlock->title=(char*)malloc(strlen(title) + 1);
if (newBlock->title == NULL) {
printf("No memory can be allocated for title\n");
return (*head);
}
newBlock->artist = (char*)malloc(strlen(artist) + 1);
if (newBlock->rating == NULL) {
printf("No memory can be alocated for artist\n");
return (*head);
}
newBlock->rating = (int)malloc(sizeof(int));
if (newBlock->rating == NULL) {
printf("No memory can be alllocated for rating \n");
return (*head);
}
strcpy(newBlock->title, title);
strcpy(newBlock->artist, artist);
newBlock->rating = rating;
newBlock->next = (*head);
newBlock->prev = NULL;
if ((*head) != NULL)
(*head)->prev = newBlock;
(*head) = newBlock;
return (*head);
}
void printSongInfo(SongNode* head) {
SongNode* ptr;
ptr = head;
printf("\n");
printf("%-35s %-35s %-35s\n", "Title", "Artist","Rating");
while (ptr != NULL) {
printf("%-35s %-35s %-35d\n", ptr->title, ptr->artist);
ptr = ptr->next;
}
}
You have a break statement in the while (rating = getnum()) loop that shouldn't be there. It will cause the loop to terminate before getting any song info.
Other problems:
newBlock->rating = (int)malloc(sizeof(int)); will leak memory, because you allocate some but never free it. Because rating is an int, memory does not need to be allocated for it. (Also, see Do I cast the result of malloc?).
getSongInfo should either return the new head, or update the current one, but not both.
Updating tail is similar to updating head, but does not need to be done all the time when inserting at the head (there's a condition that you'll need to check for).
You don't need #pragma once in a C source file. That should be in a header (and is only supported on some compilers).
Upon running the code below i get the output
NAME: (null) | GPA: 0.000000 | YEAR: (NULL)
are the linked lists not implemented correctly? I am currently using a makefile and bringing in a test.data file with names and gpa and senior/ect..
Ollie 2.9 freshmen
John 3.2 senior
Julie 2.2 freshmen
Joe 1.8 freshmen
Mary 3.8 senior
Sue 3.4 junior
Jane 2.7 senior
Bob 2.8 senior
Fred 3.2 freshmen
Bill 3.3 junior
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "students.h"
Student *top = NULL;
Student *temp, *temp1, *temp2;
// Creates the entire linked list from the file.
// Should call readNext and push
// Returns head of the linked list
Student *buildStudentList()
{
Student *p;
p = readNext();
push(&top, p);
return top; //TODO: Change return
}
//Read a single line from standard input and return a student structure located on the heap
Student *readNext()
{
Student *s =(Student*) malloc(sizeof(Student));
scanf("%s", s -> name);
scanf("%f", &s -> gpa);
scanf("%s", s -> year);
s->next = NULL;
return s; //TODO: Change return
}
//Return a student structure stored on the heap
Student *makeStudent(char *name, float gpa, char *year)
{
Student *s =(Student*) malloc(sizeof(Student));
s -> name = name;
s -> gpa = gpa;
s -> year = year;
s -> next = NULL;
return s; //TODO: Change return
}
//insert a new student node at the head of the linked list
void push(Student **list, Student *student)
{
top = *list;
student -> next = top;
top = student;
}
//Insert a student node in the desired position on the linked list
void insert(Student *list, Student *s, int position)
{
int i;
top = list;
temp = top;
for(i = 1; i < position -1; i++)
{
temp = temp -> next;
}
if(temp == NULL)
{
//blank
}
else
{
s -> next = temp -> next;
temp -> next = s;
}
}
//Displays contents of a single student structure
void display(Student *s){
printf("NAME:%s | GPA: %f | YEAR:%s
", s -> name, s-> gpa, s -> year);
}
//Displays contents of the entire linked list
void displayAll(Student *list)
{
temp = list;
while(temp != NULL)
{
display(temp);
temp = temp -> next;
}
}
//Delete all data allocated on the heap before terminating program
void cleanUp(Student *list)
{
temp1 = list;
temp2 = temp1 -> next;
while(temp1 != NULL)
{
free(temp1);
temp1 = temp2;
}
if(temp2 != NULL)
{
temp2 = temp2 -> next;
}
}
//Main function tests your functions.
int main()
{
printf("Program Started
");
//Construct Linked List from Standard Input
Student *list = buildStudentList();
//Insert a new student in desired position
Student *s = makeStudent("Max",3.0, "senior");
insert(list, s, 3);
//Display entire linked list
displayAll(list);
//Free all heap memory
cleanUp(list);
printf("Program Successful Exit
");
exit(EXIT_SUCCESS);
}
Since you didn't post your struct definition, I had to guess whether (e.g.) name was char *name; or (e.g. char name[100];). Within the code, it used it as a pointer.
So ...
Your readNext and makeStudent don't allocate space for the strings (char * pointers) name and year, so they're probably segfaulting.
insert takes Student *list when it really needs Student **list.
IMO, you should have a separate List type to avoid confusion (that has a single element: Student *head;). So, wherever you have Student *list, you replace it with List *list
When you do that, you don't have to pass down Student ** [a double star] pointer when you mean a list. Using list->head is a lot easier and more descriptive than *list.
Also, be consistent. Some functions take Student **list if they modify the list [they have to]. Others use Student *list, but they should be consistent as well.
No need for the various global scope temp variables. These should be function scoped and use more descriptive names.
Your insert has issues. It will orphan the node it's trying to insert if no position match is found (e.g. insert at position 99 in your example). Usual is to insert at tail or return an error code. Also, it wasn't totally clear what position meant [to me], because of the code you had. It could have been "insert before" or "insert after" the Nth node.
You can't insert a literal newline in a double quoted string. So, use the \n escape sequence (e.g.) printf("hello world\n");
Also, functions that take no arguments should use void (e.g.) instead of int main(), use int main(void).
Here's a cleaned up version of your code, incorporating what I've mentioned above:
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
//#include "students.h"
typedef struct student Student;
struct student {
Student *next;
float gpa;
char *name;
char *year;
};
typedef struct list {
Student *head;
} List;
//insert a new student node at the head of the linked list
void
push(List *list, Student *student)
{
student->next = list->head;
list->head = student;
}
//Return a student structure stored on the heap
Student *
makeStudent(char *name, float gpa, char *year)
{
Student *s = (Student *) malloc(sizeof(Student));
s->name = strdup(name);
s->gpa = gpa;
s->year = strdup(year);
s->next = NULL;
return s;
}
//Read a single line from standard input and return a student structure located on the heap
Student *
readNext(void)
{
char name[1000];
float gpa;
char year[1000];
Student *s = NULL;
int count = scanf("%s %f %s",name,&gpa,year);
if (count == 3) {
printf("readNext: name='%s' gpa=%g year='%s'\n",name,gpa,year);
s = makeStudent(name,gpa,year);
}
return s;
}
// Creates the entire linked list from the file.
// Should call readNext and push
// Returns head of the linked list
List *
buildStudentList(List *list)
{
Student *p;
while (1) {
p = readNext();
if (p == NULL)
break;
push(list, p);
}
return list;
}
//Insert a student node in the desired position on the linked list
int
insert(List *list, Student *s, int position)
{
Student *cur;
Student *prev;
int i;
int goflg;
//position -= 1;
#if 0
i = 1; // insert before Nth position
#else
i = 0; // insert after Nth position
#endif
prev = NULL;
for (cur = list->head; (cur != NULL) && (i < position);
++i, cur = cur->next) {
prev = cur;
}
// this may not be needed -- usual is to insert at tail if position is not
// found -- this will orphan the node to be inserted
#if 0
goflg = (i == position);
#else
goflg = 1;
#endif
if (goflg) {
s->next = cur;
if (prev != NULL)
prev->next = s;
else
list->head = s;
}
return goflg;
}
//Displays contents of a single student structure
void
display(Student *s)
{
printf("NAME:%s | GPA: %f | YEAR:%s\n", s->name, s->gpa, s->year);
}
//Displays contents of the entire linked list
void
displayAll(List *list)
{
Student *temp = list->head;
while (temp != NULL) {
display(temp);
temp = temp->next;
}
}
//Delete all data allocated on the heap before terminating program
void
cleanUp(List *list)
{
Student *cur;
Student *next;
for (cur = list->head; cur != NULL; cur = next) {
next = cur->next;
free(cur->name);
free(cur->year);
free(cur);
}
list->head = NULL;
}
//Main function tests your functions.
int
main(void)
{
List top = { NULL };
List *list;
printf("Program Started\n");
//Construct Linked List from Standard Input
list = buildStudentList(&top);
//Insert a new student in desired position
Student *s = makeStudent("Max", 3.0, "senior");
insert(list, s, 3);
//Display entire linked list
displayAll(list);
//Free all heap memory
cleanUp(list);
printf("Program Successful Exit\n");
exit(EXIT_SUCCESS);
}
I am writing a program that has names and ages entered into it. The names can then be called and the age of the person will be printed out. If the person does not exist in the list it prints their age as -1. If a name is entered with a new age that is already in the list, the new entry is not added. Currently it appears the names are sorted by the order that I input them. How can I sort them alphabetically by only changing the code for the function add? This code is compileable and works as intended except for the non-alphabetized list.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct person {
char *name;
int age;
struct person *next;
} Person;
void print(Person *); // prints the entire list
Person *add(Person *, char *, int); // adds a new node to the list
int getAge(Person *, char *); // returns the age of the person or -1 if not found
int main(void) {
char input1[100];
int input2;
Person *myList = NULL;
printf("Enter a person's name (one word) and age : ");
scanf("%s %d", input1, &input2);
while (input2 != 0) {
myList = add (myList, input1, input2);
printf("\n\nThe list is now : "); print(myList);
printf("Enter a name (one word) and age, enter 'xxx' and 0 to exit : ");
scanf("%s %d", input1, &input2);
}
printf("\n\nThe final list is "); print(myList);
printf("\n\nEnter the name of a person to look up their age : ");
scanf("%s", input1);
while ( strcmp(input1, "xxx") != 0 ) {
printf("\t%s is %d years old\n", input1, getAge(myList, input1) );
printf("Enter a name to look up their age or 'xxx' to exit : ");
scanf("%s", input1);
}
return 0;
}
void print(Person *ptr) {
while (ptr) { printf("[%s-%d] ", ptr->name, ptr->age); ptr = ptr->next; }
printf("\n");
return;
}
//adds person to list if the person does not exist already
Person *add(Person *ptr, char *n, int a) {
Person *newNode = malloc( sizeof(Person) );
int duplicate = 1;
Person *dummy = ptr;
while (dummy) {
if(strcmp(dummy->name, n) == 0) {
printf("Name Already Exists in List! Please retry with other name..\n");
duplicate=-1;
break;
}
else
dummy = dummy->next;
}
if (duplicate!=-1) {
newNode->name = malloc( strlen(n) + 1 );
strcpy(newNode->name, n);
newNode->age = a;
newNode->next = ptr;
return newNode;
}
duplicate = 1;
return ptr;
}
//function to find age of the passed person
int getAge(Person *ptr, char *name) {
while (ptr) {//while loop to traverse entire linked list elements (All persons one by one)
if(strcmp(ptr->name, name) == 0) //comparing person name in the list with the search key name
return ptr->age; //if found, returning the age of that person
else
ptr = ptr->next; //if not found, check in next node of linked list
}
return -1; // if not found, even after visting all nodes, return -1
}
You can do an insertion sort. Each time you add a new record, you scan through the list to see where it belongs and insert it there. This could be combined with your scan for duplicates.
Person *add(Person *head, char *n, int a) {
char empty[1] = "";
Person sentinel = {0};
sentinel.name = empty;
sentinel.next = head;
Person *p = &sentinel;
while (p) {
int cmp = p->next ? strcmp(n, p->next->name) : -1;
if (cmp == 0) {
printf("Name Already Exists in List! Please retry with another name..\n");
break;
}
if (cmp < 0) {
Person *newNode = malloc( sizeof(Person) );
newNode->name = malloc( strlen(n) + 1 );
strcpy(newNode->name, n);
newNode->age = a;
newNode->next = p->next;
p->next = newNode;
break;
}
p = p->next;
}
return sentinel.next; // a possibly-updated copy of head
}
Insertion sort always compares the new element to the next element (rather than to the current element). This makes dealing with the first element awkward, especially in a list. We get around that with a temporary "sentinel" that we pretend is just before the head of the list.
There are other approaches. You can create the new node at the head of the list and then slide it down until it's in position. If you encounter a duplicate, you remove the new one and patch up the list. Insertion sorts in other data structures typically work from the tail back toward the head, but that won't work with a singly-linked list.
I wrote something similar where I sorted student ID's. You should try doing a swap. Declare a temp variable and used that to swap. The code is something like.
int temp,
first_name,
last_name;
temp = first_name;
first_name = last_name;
last_name = temp;
Hope that gives you an idea!
Edit: What the other person suggested is a good idea as well, an insertion sort.
Your question has already been answered, but I'd like to point out another approach to adding a node. The list is defined by its head node. When iserting elements, the head node may change. (It will change in your current code, which adds elements at the front.) In order to reflect the change, you return the new head:
myList = add(myList, input1, input2);
This is redundant, because you have to specify myList twice. It is also legal to discard the result returned from a function, so there is the possibility of an error. If you pass in a pointer to the head pointer, you will eliminate the redundancy.
add(&myList, input1, input2);
The ยด&will indicate thatmyList` may change. And you can now use the return value for something else, for example a pointer to the newly inserted node or null if the name was already there.
Inserting a person at the front (unconditionally) looks like this:
Person *add_front(Person **ptr, const char *name, int age)
{
Person *p = person_new(name, age);
p->next = *ptr;
*ptr = p;
return p;
}
Inserting at the end requires to walk the list first:
Person *add_back(Person **ptr, const char *name, int age)
{
Person *p = person_new(name, age);
while (*ptr) {
ptr = &(*ptr)->next;
}
p->next = *ptr;
*ptr = p;
return p;
}
Note how you do not need to treat the empty list as a special case. Adrian's solution eliminates the special case with a sentinel element. Here, it is eliminated by the pointer itself: ptr points to the list head pointer in the calling function at first. As you walk through the list, it points to the next pointer of the previous node. Updating *ptr updated the pointer that took us to the current node.
The function person_new creates a new node. I find it tidier to make this a separate function, which you could call from other functions:
Person *person_new( const char *name, int age)
{
Person *p = malloc(sizeof(*p));
p->name = malloc(strlen(name) + 1);
strcpy(p->name, name);
p->age = age;
p->next = NULL;
return p;
}
Now the function you want, which inserts the node in alphabetical order, looks like this:
Person *add(Person **ptr, const char *name, int age)
{
while (*ptr && strcmp((*ptr)->name, name) < 0) {
ptr = &(*ptr)->next;
}
if (*ptr == NULL || strcmp((*ptr)->name, name) != 0) {
Person *p = person_new(name, age);
p->next = *ptr;
*ptr = p;
return p;
}
return NULL;
}
When you look up a node by name, you can stop the search short when the current node is alphabetically larger than the name you're looking for:
const Person *find(const Person *ptr, const char *name)
{
while (ptr) {
int cmp = strcmp(ptr->name, name);
if (cmp > 0) break;
if (cmp == 0) return ptr;
ptr = ptr->next;
}
return NULL;
}
You can see the code in action here.
So I'm creating a linked list in C and adding some nodes to it that contain information. I have an if else statement where I create the linked list's head and then add nodes to it. The problem is that when I add a new node I seem to lose the old one. Not sure why this is happening or how to fix this.
Edit: I have made some updates to make it a runnable program.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<stdint.h>
#include<regex.h>
int main(int argc, char argv[]) {
int head=0, i=0;
char tempCourseID[10], tempCourseGrade[10], tempCourseCH[10];
static struct LinkedList {
char *CourseName;
char *CourseGrade;
char *CourseCreditHours;
struct LinkedList *next;
} LinkedList;
static struct LinkedList *first, *savefirst, *headlist;
first = malloc(sizeof ((*first)));
savefirst = first;
headlist = first;
for(i ; i<5; i++){
printf("Enter Course name");
fgets(tempCourseID, sizeof(tempCourseID), stdin);
printf("Enter Course grade");
fgets(tempCourseGrade, sizeof(tempCourseGrade), stdin);
printf("Enter Course credit hours");
fgets(tempCourseCH, sizeof(tempCourseCH), stdin);
//checks to see if linked list head exists
if (head == 0) {
printf("No head has been found.\n");
headlist->CourseName = tempCourseID;
headlist->CourseGrade = tempCourseGrade;
headlist->CourseCreditHours = tempCourseCH;
headlist->next = NULL;
printf("A head has been created\n");
printf("A node has been added\n");
head = 1;
} else {
printf("Ahead already exists\n");
first = malloc(sizeof ((*first)));
first->CourseName = tempCourseID;
first->CourseGrade = tempCourseGrade;
first->CourseCreditHours = tempCourseCH;
first->next = NULL;
savefirst->next = first;
savefirst = first;
printf("A node has been add\n");
head = 1;
}
}
while (headlist != NULL) {
printf(" %s ", headlist->CourseName);
printf(" %s ", headlist->CourseGrade);
printf("%s \n", headlist->CourseCreditHours);
headlist = headlist->next;
}
return 0;
}
You have char tempCourseID[10] and char* CourseName
It is legal to use CourseName = tempCourseID; however tempCourseID is temporary, and so the string will be lost soon. In this case we need to allocate separate memory for CourseName, and then copy the value from tempCourseID
Use instead
CourseName = malloc(strlen(tempCourseID) + 1);//add +1 for null-character
strcpy(CourseName, tempCourseID);
//or
CourseName = strdup(tempCourseID)//shortcut!
There are problem with the linked list. You have too many variables with similar names. A linked list needs only head. You can introduce a temporary variable node for adding new nodes. If you are adding nodes to the tail, then save the last node in the list, lets call it savenode
In this example I removed fgets functions and replaced it with sprintf, that's just to make it easier to run the program and debug. You can put back fgets later.
int main(int argc, char argv[])
{
struct LinkedList
{
char *CourseName;
char *CourseGrade;
char *CourseCreditHours;
struct LinkedList *next;
};
int i;
char tempCourseName[100], tempCourseGrade[100], tempCourseCH[100];
struct LinkedList *head = NULL;
struct LinkedList *node = NULL;
struct LinkedList *savenode = NULL;
for(i = 0; i < 5; i++)
{
sprintf(tempCourseName, "CourseName %d", i);
sprintf(tempCourseGrade, "tempCourseGrade %d", i);
sprintf(tempCourseCH, "tempCourseCH %d", i);
node = malloc(sizeof(*node));
node->CourseName = strdup(tempCourseName);
node->CourseGrade = strdup(tempCourseGrade);
node->CourseCreditHours = strdup(tempCourseCH);
node->next = NULL;
if(head == NULL)
head = node;
//check savenode exists
//this will be the last node (tail) in the existing list
//get it to point to our new node
if(savenode)
savenode->next = node;
//now we have a new tail
savenode = node;
}
//walk through the list
node = head;
while(node)
{
printf("%s, %s, %s\n",
node->CourseName, node->CourseGrade, node->CourseCreditHours);
node = node->next;
}
return 0;
}