C: Adding data to structure using linked list - c

I'm new to c and learning about linked lists, I decided to create a library manager to manage my books using linked list but it doesn't seem to be saving the data to the structure using linked list. When someone tries to add a new book the function hits the checkID function to see if the book with the same id already exists but when i do a display information nothing seems to exists in the structure.
void addBook()
{
int bookId;
BOOK *head = NULL, *temp;
temp = (BOOK*) malloc(sizeof(BOOK));
printf("\n Enter Book Details\n");
printf("Enter book ISBN: ");
scanf("%d", &bookId);
int bInd = checkID(bookId);
if (bInd == 0)
{
printf("Enter book title: ");
scanf("%s", &temp->chTitle);
printf("Enter book type (eg. magazine, novel): ");
scanf("%s", &temp->chType);
printf("Enter book publisher (eg. UTA): ");
scanf("%s", &temp->chPublisher);
printf("Enter book's number of pages: ");
scanf("%d", &temp->nPages);
printf("Enter book's price: ");
scanf("%f", &temp->nPrice);
printf("Enter year published: ");
scanf("%d", &temp->nPubYear);
//temp->next=NULL;
if (head == NULL)
{
head = temp;
temp->next = NULL;
}
else{
temp->next = head;
head = temp;
}
//BOOK[count].nStatus = IN;
count++;
}
else
{
printf("\nSorry another book with that id: Try again!\n" );
addBookFunction();
}
}
int checkID(int t)
{
BOOK *head;
while (head != NULL)
{
if (head->nID == t)
return 1;
head = head->next;
}
return 0;
}

Don't worry ! It's normal ! You are creating a new book library each time you add a book ! :)
At your place, an easy way to solve it would be to pass your "Library collection of book" to your AddBook method :
void addBook(BOOK *libraryBooks)
int checkID(BOOK *libraryBooks, int t)
Then remove your variable declaration 'head'. Change all 'head' by 'libraryBooks' and pass the variable to checkID.
Above this function you'll have to manage your library.

checkID() and addBook() should probably both accept the head of your linked list as an additional parameter. The head pointer that iterates through your linked list in checkID() looks like it's getting used before it's initialized with a proper value. It may just be lucky happenstance that you haven't hit a null pointer exception already.

Related

How to break out of this for loop?

I am writing a program in which I add students to a roster using linked lists. I am successful at adding the first student, but upon adding subsequent students, my program prints "Student already exists" even when the student doesn't exist yet. Below is my add function.
struct student *add(struct student *list){
struct student *p;
struct student *new_student = malloc(sizeof(struct student));
printf("Enter the student's last name: ");
read_line(new_student->last, NAME_LEN);
printf("Enter the student's first name: ");
read_line(new_student->first, NAME_LEN);
printf("Enter the student's email: ");
read_line(new_student->email, EMAIL_LEN);
printf("Enter the student's instrument: ");
read_line(new_student->instrument, INSTRUMENT_LEN);
printf("Enter the student's group name: ");
read_line(new_student->group, GROUP_LEN);
if(new_student == NULL){
printf("\nMalloc failed.\n");
return list;
}
if(list==NULL){
return new_student;
}
for(p=list;p!=NULL; p=p->next){
if((strcmp(p->first,new_student->first)==0) &&
(strcmp(p->last, new_student->last)==0)){
printf("\nThis student already exists.\n");
return list;
}
else{
while(p->next==NULL){
p->next = new_student;
new_student->next = NULL;
printf("\nStudent has been added to the roster.\n");
break; //FOR LOOP NOT BREAKING?
}
}
}
return new_student;
}
If anyone can help me understand how to fix this so that the for loop doesn't keep executing after the student is added to the list, I'd appreciate it.
It doesn't seem as though my break statement is working. I've tried making the return to new_student occur within my else statement, but that causes other issues in my program. Any help is appreciated.
printf("\nStudent has been added to the roster.\n");
p = NULL;
break;
What worked for me was getting rid of my else statement and while loop and opting for an if statement. Also, I was only returning the student added to the list, rather than the entire list, so students were not being added.

Creating and adding data in a linked Llist

I have started learning about Linked Lists, which through videos and multiple examples I have pretty much understood what a Linked List is and how it can be represented in a real life analogy. But when it comes to coding it I get lost I suppose through all the pointers I kind of get confused, it took a bit for me to get a stronger grasp on arrays so I assume it will be the same with Linked lists. So here is my code
/*
• The program will use dynamic memory to create a singly linked list(NO ARRAYS PERMITTED)
• The program will store unlimited number of student records(limited only by RAM).
• A student record will consist of Student Name, Age, and GPA…you may need to add additional fields to make this work(Next).
• The program will have a way for the user to add records(in order by name).You can assume that no two students have the same name.The list will always be in order.
• The program will have a way for the user to display ALL records.
• The program needs a way to quit.
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#pragma warning(disable: 4996)// disables warning
typedef struct{
char name[40];
int age;
float gpa;
struct NODE* next;
}NODE;
void addStudent();
int main(void){
NODE* head = NULL;
int userinput;
printf(" **********************************\n");
printf(" * MENU *\n");
printf(" * 1. Add Student *\n");
printf(" * 2. Display all student records*\n");
printf(" * 3. Quit *\n");
printf(" **********************************\n");
scanf_s("%d%*[^\n]", &userinput); '\n' == getchar();
switch (userinput)
{
case 1: do
{
addStudent(head);
printf("Add another record? 1(y) 2(n)\n");
scanf_s("%d%*[^\n]", &userinput); '\n' == getchar();
} while (userinput == 1);
break;
}
}
void addStudent(NODE* head){
head = malloc(sizeof(NODE));
if (head == NULL)
{
return;
}
NODE * current = head;
printf("Please Enter student name:\n");
fgets(current->name, 40, stdin);
printf("Enter student age:\n");
scanf("%d%*[^\n]", &current->age); '\n' == getchar();
printf("Enter student gpa:\n");
scanf("%f%*[^\n]", &current->gpa); '\n' == getchar();
current->next;
current->next = NULL;
while (current != NULL){
current = head;
printf("%s\n", current->name);
printf("%d\n", current->age);
printf("%0.2f\n", current->gpa);
current = current->next;
}
}
When I compile, it will always print the head I assume its because of current = head within the while loop, I understand why its printing the head over but I am lost on how to arrange this code So that I can create a new node when I add and print all the nodes, through the loop.
The problem is that you never create new nodes to add to the list but always just updating the head. In order to make it work you should:
Allocate a new NODE,
NODE *newNode = malloc(sizeof(NODE));
Load the data into this node
printf("Please Enter student name:\n");
fgets(&newNode->name, 40, stdin);
printf("Enter student age:\n");
scanf("%d%*[^\n]", &newNode->age); '\n' == getchar();
printf("Enter student gpa:\n");
scanf("%f%*[^\n]", &newNode->gpa); '\n' == getchar();
Update the node to point to the node currently pointed by the HEAD
newNode->next = head
Update the head to point to the new Node
head = newNode;

adding a node to a linked list using a function

I currently have a linked list and need to add data to it that is inputted by the user from the keyboard so i have two structs:
struct CourseInfo {
int courseID;
char courseName[30];
};
typedef struct CourseInfo courseinfo;
struct StudentInfo {
char StudentID[10];
char FirstName[21];
char LastName[26];
int num_course;
courseinfo array[10];
struct StudentInfo *next;
};
So i have a linked list with 3 nodes currently. I then need to call a function and add a node. The node needs to be inserted in the correct place which is that the studentID before it needs to be less than it and the studentID after needs to be greater so the current IDs i have are 111111111, 333333333, and 444444444 and im trying to add 222222222 so it would go in the second spot so my function looks like:
studentinfo *addStudent(studentinfo *data) //returns type studentinfo* now
{
studentinfo *add;
add = malloc(sizeof(studentinfo));
add->next = NULL; //Now its set to NULL to begin
int knt;
printf("%s", "Adding new student:\nStudent ID: ");
scanf("%s", add->StudentID);
printf("%s", "First Name: ");
scanf("%s", add->FirstName);
printf("%s", "Last Name: ");
scanf("%s", add->LastName);
printf("%s", "Number of courses: ");
scanf("%d", &add->num_course);
for(knt = 0; knt < add->num_course; knt++) {
printf("%s", "Course ID: ");
scanf("%d", &add->array[knt].courseID);
printf("%s", "Course Name: ");
scanf("%s", add->array[knt].courseName);
}
if(searchStudentID(data, add->StudentID)) {
puts("immediately inside if");
while(data != NULL) {
puts("Immediately inside while");
if(strcmp(add->StudentID, data->StudentID) < 0) {
puts("inside if");
add->next = data;
data = add;
}
else {
puts("inside first else");
studentinfo *PrevPtr = data;
studentinfo *NPtr = data->next;
while(NPtr != NULL) {
("inside while(NPTR != NULL)");
if(strcmp(add->StudentID, NPtr->StudentID) < 0) {
add->next = PrevPtr;
PrevPtr->next = add;
break;
}
else {
puts("inside a differnet else");
PrevPtr = NPtr;
NPtr = NPtr->next;
}
}
if(PrevPtr->next == NULL) {
puts("inside last if");
add->next = NULL;
PrevPtr->next = add;
}
}
}
}
else {
puts("Found id");
}
return data; //returns data back to call
}
So i added all those puts statement because i wanted to see why the program kept crashing. So the puts statement puts("Inside a different else") is stuck in an infinite loop and keeps printing. The function searchStudentID simply returns 1 if we dont already have the ID and 0 if we already have it. I know that this function works so there is no need to post it.
I think the problem may be in the break; statement because it doesnt exit from the first while loop but only exits from the inner loop but im not positive.The call to this function look like:
list = addStudent(list); //Now the new data is stored in list
Where list is the linked list with 3 nodes
Linked list management is about managing node pointers, not just nodes. You want to do several things to make this considerably easier on yourself:
Separate the input step from the search+insertion step. They don't belong together regardless of how they may seem otherwise. The biggest benefit this brings to you is reducing your list insertion code to what it should be doing (and only what it should be doing): managing the linked list. I've kept yours intact, but you should really be error checking and doing the data reading somewhere else.
Use a pointer to pointer to walk the list. The biggest benefit from this is eliminating the need to special-case head-position insertion. If that is the position a new node will eventually occupy, so be it, but eliminating that special-case further reduces the complexity of the algorithm.
Don't search the list unless you're capable of retaining the search results to be used for insertion logic. It makes little sense to perform an O(N) scan of the linked list to determine if input data is already present, only to search it again to find the position said-data will actually be inserted. Do it once. Find the position where it belongs. If it is already there, do nothing, otherwise, you sit at the precipice of the proper insertion location already.
Finally, don't allocate a new node unless you know you need one. Use an automatic variable that helpfully self-discards if you end up doing nothing.
Putting all of that together gives something like this:
struct CourseInfo {
int courseID;
char courseName[30];
};
typedef struct CourseInfo CourseInfo;
struct StudentInfo {
char StudentID[10];
char FirstName[21];
char LastName[26];
int num_course;
CourseInfo array[10];
struct StudentInfo *next;
};
typedef struct StudentInfo StudentInfo;
StudentInfo *addStudent(StudentInfo *head)
{
StudentInfo **pp = &head, *p = NULL, rec;
int knt;
// TODO: error check your inputs!
printf("%s", "Adding new student:\nStudent ID: ");
scanf("%s", rec.StudentID);
printf("%s", "First Name: ");
scanf("%s", rec.FirstName);
printf("%s", "Last Name: ");
scanf("%s", rec.LastName);
printf("%s", "Number of courses: ");
scanf("%d", &rec.num_course);
for(knt = 0; knt < rec.num_course; knt++) {
printf("%s", "Course ID: ");
scanf("%d", &rec.array[knt].courseID);
printf("%s", "Course Name: ");
scanf("%s", rec.array[knt].courseName);
}
// walk the list pointers, starting with head, looking for
// a node that is equal or greater than the input node
while (*pp && (knt = strcmp((*pp)->StudentID, rec.StudentID)) < 0)
pp = &(*pp)->next;
// leave now if already present
if (*pp && knt == 0)
return head;
// allocate new node
p = malloc(sizeof *p);
if (p == NULL)
{
perror("Failed to allocate new node");
exit(EXIT_FAILURE);
}
// structure copy.
*p = rec;
// link into proper list position.
p->next = *pp;
*pp = p;
// always return the head (which may have updated above)
return head;
}
That's it. As mentioned, I would personally perform the input operation somewhere other than this function, but I leave that to you to consider.
Best of luck.
Since this function updates the list you either need it to be
studentinfo *addStudent(studentifo *data)
and return the updated head value. Or
void addStudent(studentifo **data)
and do
*data = <new thing>
Issues that I see:
You are not setting add->next to NULL.
You are changing data locally.
add->next = data;
data = add;
changes the value of data locally in the function. It does not change the value in the calling function.
You have the check
while(data != NULL)
following the if statement
if(searchStudentID(data, add->StudentID)) {
but I don't see any code to add the new student when searchStudentID(data, add->StudentID) returns false and when data == NULL to start with.

Pointing one linked list to another

My task is to store list of films in one array and store actor name in other array and make sure that film name is pointing to the respective actor.
I'm using linked list. I'm facing difficulty in storing the address of the actor into the movie structure so that it can point to it. The code is in c. Please help!
struct movie
{
char name[10];
struct movie *data;
struct movie *next;
};
typedef struct movie m;
m *insert(m *first, char actor[10], int i)
{
m *cur;
cur = (m *)malloc(sizeof(m));
printf("\nEnter movie name: ");
scanf("%s", cur->name);
printf("\nEnter actor name: ");
scanf("%s", actor);
cur->data = &actor;
cur->next = first;
printf("\n%d", &actor);
printf("\n%d", cur->data);
printf("\n%s", actor);
printf("\n%s", *cur->data);
return (cur);
}
int main()
{
m *first = NULL, *ptr = NULL, *ptr1;
char actor[10];
int i = 0, ch;
first = (m *)malloc(sizeof(m));
ptr = (m *)malloc(sizeof(m));
do
{
printf("\n1.Enter movie: ");
printf("\n2.Search movie: ");
printf("\n3.Exit");
printf("\nEnter your choice: ");
scanf("%d", &ch);
switch(ch)
{
case 1:
first = insert(first, actor, i);
break;
case 2:
if(first == NULL)
{
printf("\nList Empty!");
break;
}
else
{
printf("\nEnter movie name: ");
scanf("%s", ptr->name);
ptr1 = first;
while(ptr1->next != NULL)
{
if(strcmp(ptr->name, first->name)==0)
{
printf("\n%s", &ptr->data);
break;
}
else
{
printf("\nNot found");
}
ptr1 = ptr1->next;
}
}
break;
}
}while(ch != 3);
}
Ok, I assume you want to store the actor name on the data part of your movie struct. If this is the case, then it's best practice to use descriptive names for variables. So I would change the struct to
struct movie
{
struct char name[10];
struct actor_t *actor; //we will define that later
struct movie *next;
};
Ok, no you need to actually create that actor structure. Do you need to store anything other than the actor name? If you need just a name then you could simply do:
struct actor_t
{
char name[10];
struct actor_t *next;
}
I suppose that the actors should be in a list too (and not an array as you wrote), that's why you need a next pointer to navigate to all the actors.
(Tip: if this task is for educational purposes, then you are probably ok with that. It would be much more efficient though to utilize a hash table to search for an actor by name)
Each time you get (via scanf) an actor name, you must make some space for an actor list node.
struct actor_t *new_actor = malloc(sizeof(*new_actor));
Now that you ve created space for a new actor, copy the string that you just got from the input into the actor structure:
strncpy(new_actor->name, actor, strlen(actor));
Ok, you ve got your first actor now. Initially, it's the only node in the actors list, so you want to set the next pointer to null.
new_actor->next = NULL;
Supposing that you have already malloced space for a movie node, make that movie's actor point to the actor node you just created:
cur->actor = new_actor;
Now if you have another movie, with the same actor you could just point to that same actor like this:
next_movie->actor = new_actor; //or whatever nave you gave to the first actor node
A few thoughts: It does not seem normal for a movie to point to just one actor. Are you sure that is your task? Does your movie need to point to several actors? If yes, that is a completely different problem.
You must work this code out. I just gave you some ideas on how to accomplish some simple tasks, but basically you need some practice on list manipulation. And ofc get your hands dirty.

Issue when comparing a value in a linked list in C

I'm working on a "simple" program in C, where we create a linked list with a structure that acts as a movie which stores, a title, year it was made, rating (1-5), and a pointer to the next node. We are not allowed to add anything to this structure, or define functions.
On top of that, we (for some reason) are required to write the entire linked list in the body of main(), so that adds a certain layer of spaghetti to the problem. Anyways, in this program, we are supposed to have the user enter either 'U' for update or 'S' for search for a movie. The update does what you would expect, you enter a title, year, rating. From this, we are supposed to insert the node at the end of the linked list.
Our search should iterate through this linked list and if it finds a match, should print out the movie, title, and year.
Although the update part of my code works, I can't seem to get search to work. I'm using a movie struct called temp, that starts at head and iterates through the list in an attempt to find the movie. After running some tests through printf, I'm finding that temp is just a null node no matter what, and no matter what movies I enter.
I am assuming this has something to do with the way I'm calling malloc? Or something to do with not assigning nodes correctly? I'm honestly not sure, and unfortunately, the lab's TA had no idea what was wrong either D:
Here is my code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct movie_node {
char title[250];
int year;
unsigned char rating;
struct movie_node *next;
};
typedef struct movie_node movie;
int main() {
// variables
int loop = 1;
movie *head = NULL; // represents first
movie *current; // represents the last node
movie *temp; // used for traversing the linked list
head = malloc(sizeof(movie));
int amountOfMovies = 0; // increment after each addition
char choice; // either 'u' (update) or 's' (search)
// ask user for input
while(loop) {
printf("%d Movie(s) in the database. Update or search (U/S): ", amountOfMovies);
scanf(" %c", &choice);
/* CHOICE 1, UPDATE */
if(choice == 'U') {
// case 1, head is null, we must create a new node
if(head == NULL) {
// get input
printf("Name of the movie: ");
scanf(" %[^\n]%*c", head->title);
printf("Year: ");
scanf("%d", &head->year);
printf("Rating: ");
scanf("%hhu", &head->rating);
head->next = NULL;
head = current; // set head to point to current
} else {
current = head;
// need to find where current is
while(current != NULL) {
current = current->next;
} // end while
// current is now at the null position, indicating empty node
current = malloc(sizeof(movie)); // allocate mem
// get user input
printf("Name of the movie: ");
scanf(" %[^\n]%*c", current->title);
printf("Year: ");
scanf("%d", &current->year);
printf("Rating: ");
scanf("%hhu", &current->rating);
current->next = NULL;
} // end else
// output movie
printf("Movie \"%s\" is added to the database.\n", current->title);
amountOfMovies++; // increment amount of movies in database
} else if(choice == 'S') {
/* CHOICE 2, SEARCH */
// temp string
char tempTitle[250];
// flag to let us know if we found something
bool found = false;
// temp linked list to traverse
temp = head;
temp = malloc(sizeof(movie));
// ask user for input
printf("Name of movie: ");
scanf(" %[^\n]%*c", tempTitle);
printf("NAME OF MOVIE IN HEAD: %s\n", temp->title); // test, take out later
while(temp != NULL) {
printf("NAME OF CURRENT MOVIE TO COMPARE TO: %s\n", temp->title); // test
if(strcmp(temp->title, tempTitle) == 0) {
// match
printf("Year: %d\n", temp->year);
printf("Rating: %hhu\n", temp->rating);
found = true;
break;
} else { // no match so far
temp = temp->next;
printf("HAVEN'T FOUND MATCH, NEXT TITLE TO CHECK IS: %s\n", temp->title); // test print
found = false;
} // end else
} // end while
if(found == false) { // no match confirmed
printf("Movie \"%s\" does not exist in the database.\n", tempTitle);
}
} else { // choice is invalid
loop = 0; // exit
} // end if-else
} // end while
// free all the nodes
return 0;
}
Note: the only thing I haven't implemented yet is freeing the memory.. which I'm not a hundred percent sure how I should accomplish it.
Any help is greatly appreciated..
The problem is with your malloc() calls. First you do:
movie *head = NULL;
// ...
head = malloc(sizeof(movie));
This means that head is no longer null and you won't be able to insert first movie the way you want to - move that malloc() somewhere else.
Secondly, few lines of code below, you do:
current = head; // <- this is OK
// ...
current = malloc(sizeof(movie)); // allocate mem <- this is NOT OK, for the same reason as before
Also, you can read titles of the movies like that: scanf("%249s", head->title).
Let me know if you know how to go from there.
Apart from the problems in your code, there is another problem: the lab's TA had no idea what was wrong either.
sample to fix
movie *new_node(void){//aggregate the creation of a new node
movie *node = malloc(sizeof(*node));//error check omit
printf("Name of the movie: ");
scanf(" %249[^\n]%*c", node->title);
printf("Year: ");
scanf("%d", &node->year);
printf("Rating: ");
scanf("%hhu", &node->rating);
node->next = NULL;
return node;
}
int main() {
int loop = 1;
movie *head = NULL;
movie *current;
movie *temp;
//head = malloc(sizeof(movie));//"if(head == NULL) {" don't work
int amountOfMovies = 0;
char choice;
while(loop) {
printf("%d Movie(s) in the database. Update or search (U/S): ", amountOfMovies);
scanf(" %c", &choice);
if(choice == 'U') {
if(head == NULL) {
current = head = new_node();//need set to current
} else {
current = head;
while(current->next != NULL) {//"current != NULL" can't link
current = current->next;
}
current = current->next = new_node();
}
printf("Movie \"%s\" is added to the database.\n", current->title);
amountOfMovies++;
} else if(choice == 'S') {
char tempTitle[250];
bool found = false;//need <stdbool.h>
temp = head;
//temp = malloc(sizeof(movie));//Unnecessary
printf("Name of movie: ");
scanf(" %249[^\n]%*c", tempTitle);
//printf("NAME OF MOVIE IN HEAD: %s\n", temp->title);
while(temp != NULL) {
//printf("NAME OF CURRENT MOVIE TO COMPARE TO: %s\n", temp->title);
if(strcmp(temp->title, tempTitle) == 0) {
printf("Year: %d\n", temp->year);
printf("Rating: %hhu\n", temp->rating);
found = true;
break;
} else {
temp = temp->next;
printf("HAVEN'T FOUND MATCH, NEXT TITLE TO CHECK IS: %s\n", temp->title);
//found = false;//Unnecessary
}
}
if(found == false) {
printf("Movie \"%s\" does not exist in the database.\n", tempTitle);
}
} else {
loop = 0;
}
}
// free all the nodes
return 0;
}

Resources