Pointing one linked list to another - c

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.

Related

Having trouble creating a linked list

Sorry for the vague title, i'm not quite sure how to explain what is going on. I am attempting to create a linked list, with each entry of the linked list containing two character strings, one integer array that can hold four entries, and one float array that can hold four entries.
Here is the initialization of the main struct in a header file -
#ifndef FUNCTIONS_H
#define FUNCTIONS_H
#define MAX_LENGTH 20
struct stock {
char ticker[MAX_LENGTH];
char comp[MAX_LENGTH];
int shares[4];
float price[4];
struct stock *next;
};
#endif
Here is the code from my main file -
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "functions.h"
void main(void) {
int choice,shr[4], i;
char tic[MAX_LENGTH];
char nam[MAX_LENGTH];
float pri[4];
struct stock *head = NULL;// entry point for linked list
struct stock *current; //pointer currently being used
printf("Press 1 to enter a new stock\n");
printf("Press 2 to find the LIFO and FIFO dollar cost average for the number of shares sold\n");
scanf("%d", &choice);
switch(choice)
{
case 1:
printf("Enter the stock ticker:\n");
scanf("%s", &tic);
printf("Enter the name of the stock:\n");
scanf("%s", &nam);
for(i = 1; i<=4; i++) {
printf("Enter the number of shares:\n");
scanf("%d",&shr[i] );
printf("Enter the price of the stock:\n");
scanf("%f", &pri[i]);
}
if(head == NULL) { //check to see if first element has been filled
head = (struct stock *)malloc(sizeof(struct stock));
current = head;
}
else { //if the first element is full, move on to the next entry
current->next = (struct stock *)malloc(sizeof(struct stock));
current = current->next;
}
strcpy(current->ticker, tic);
strcpy(current->comp, nam);
memcpy(current->shares, shr, sizeof(current->shares));
memcpy(current->price, pri, sizeof(current->price));
current->next = NULL;
}
printf("%s\n", current->ticker);
printf("%s\n", current->comp);
for(i = 1; i <= 4; i++) {
printf("%d\n", current->shares[i]);
printf("%f\n", current->price[i]);
}
}
The end goal of the program is to have two separate stock entries, and be able to calculate the FIFO/LIFO dollar cost average based on four different share purchases for each stock. But for now, i am only trying to be able to correctly enter the information into a linked list.
After the loop that asks the user four times for the number of shares, and price of a stock, the character string "nam" asked for previously seems to disappear, because if i try to access it or print it out later it prints nothing.
I am trying to use the memcpy function to copy an inputted array over to the one in the linked list. Whenever i try to print the array back out after i copied it to the linked list, it does not print properly. The first three entries of the shares and price arrays print properly, but the fourth share entry prints a huge number and the fourth float entry prints as zero.
Thanks for any help.
tic and nam are already pointers so change
scanf("%s", &tic);
scanf("%s", &nam);
to
scanf("%s", tic);
scanf("%s", nam);
Also, not directly related to your issue, but
head = (struct stock *)malloc(sizeof(struct stock));
current->next = (struct stock *)malloc(sizeof(struct stock));
would be better written as
head = malloc(sizeof(*head));
current->next = malloc(sizeof(*(current->next)));
There is no need to cast the return from malloc() and by using sizeof(*head) you are guaranteed to be using the correct type for sizeof.

Printing all "members" of a struct

I have nested-structs (shown below)
in slist* add_student() I am adding new students to the list
void print_student() should print the list
void print_students(slist* students){
slist *tempS = students;
while(tempS){
printf("%d:%s\n", tempS->info->id, tempS->info->name);
tempS = tempS->next;
}
}
slist* add_student(slist *students, char *name, int id){
student* tempStudent;
tempStudent = (student *)malloc(sizeof(student));
tempStudent->id = id;
tempStudent->name = (char*)malloc(strlen(name)+1);
strcpy(tempStudent->name, name);
slist *news;
news=(slist *)malloc(sizeof(slist));
news->info = tempStudent;
news->next = students;
return news;
}
Now the problem is it is only printing the last entered "student", and I can't seem to tell which function is doing it the wrong way, so the question is, is it doing it wrong because I am using newly defined part to the struct (slist* tempS = students in void print_students()) for example? or does it have to do with the next (in both functions)?
an example of an I/O would be
and another...
The struct and main I use, if anyone wants to look at them
static void getstring(char *buf, int length) {
int len;
buf = fgets(buf, length, stdin);
len = (int) strlen(buf);
if (buf[len-1] == '\n')
buf[len-1] = '\0';
}
int main() {
slist* students = 0;
char c;
char buf[100];
int id, num;
do {
printf("Choose:\n"
" add (s)tudent\n"
" (p)rint lists\n"
" (q)uit\n");
while ((c = (char) getchar()) == '\n');
getchar();
switch (c) {
case 's':
printf("Adding new student.\n");
printf("Student name: ");
getstring(buf, 100);
printf("Student ID: ");
scanf("%d", &id);
students = add_student(students, buf, id);
break;
case 'p':
printf("Printing Information.\n");
print_students(students);
break;
}
if (c != 'q')
printf("\n");
} while (c != 'q');
return 0;
}
// structures
typedef struct student {
char *name;
int id;
struct clist *courses;
} student;
typedef struct course {
char *title;
int number;
struct slist *students;
} course;
typedef struct slist {
student *info;
struct slist *next;
} slist;
typedef struct clist {
course *info;
struct clist *next;
} clist;
In general, pick up a piece of paper and a pencil and draw what your code does; that's a pro tip for finding what's wrong with your list when in trouble!
Your code is fine* now, and let me explain you why.
So, if you do so you will see that when the first student arrives, you allocate space for him/her and then populate that struct correctly. tempStudent points to that struct.
Then, news will create a new struct that is the struct that handles the list. Its info field is set to the newly created student and next points to students, which I guess is NULL when the first student is added.
Then you return news and students now points to it.
Now we are about to add the second student. We create his struct - so far so good!
We again create the struct news which handles the list. It will assign info to newly created student and next will point to students, which is what we want.
Then you return news and students now points to it.
That way of course the newly created student will be places first in the list, despite the fact we added him/her secondly.
As a result, you will get something like this:
Georgioss-MacBook-Pro:~ gsamaras$ gcc -Wall main.c
Georgioss-MacBook-Pro:~ gsamaras$ ./a.out
Choose:
add (s)tudent
(p)rint lists
(q)uit
s
Adding new student.
Student name: Leon
Student ID: 1
Choose:
add (s)tudent
(p)rint lists
(q)uit
s
Adding new student.
Student name: kate
Student ID: 2
Choose:
add (s)tudent
(p)rint lists
(q)uit
p
Printing Information.
2:kate
1:Leon
which is OK.
*Of course you have to write other functions as well, such as deleting your list and de-allocating the space you already allocated.
Do I cast the result of malloc? No!

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.

C: Adding data to structure using linked list

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.

C, Printing more than one integer from a linked list

I'm very new to C, so I'm not totally sure what's the matter. I can't figure out how to print more than a single integer value in a function.
add function:
void add(char *name,int id,int copies)
{
/* Pointer to next item */
struct list *newAlbum;
newAlbum = malloc(sizeof(struct list));
strcpy((*newAlbum).name, name); // Set album name
newAlbum->id = id;
newAlbum->copies = copies;
newAlbum->pNext = pFirst;
pFirst = newAlbum;
}
show function:
void show()
{
system("clear");
struct list *current_node;
current_node = pFirst;
while(current_node != NULL)
{
printf("Album #%d \n",current_node->id);
printf("Album Name: %s \n",current_node->name);
printf("Album Copies:%d \n",current_node->copies);
printf("\n");
current_node=current_node->pNext;
}
}
My program prints out the current_node->id as if it were current_node->copies, and current_node->copies is printed out as 134516043, which is obviously, wrong.
I think I must be passing something wrong to the function or something, but I can't figure it out. Any tips?
I call the function add like this:
add(name,id,copies);
The list is as so:
/* THE LIST */
struct list{
char name[52];
int id;
int copies;
int sold;
struct list* pNext;
};
struct list *pFirst = NULL;
I call the function with user input with this piece of code:
printf("Enter the name of the new album. \n");
scanf("%s",&name);
printf("Enter the album id. \n");
scanf("%d",&id);
printf("Enter number of copies. \n");
scanf("%d," &copies);
// Pass data to add()
add(name,id,copies);
Your code that you've shown is OK, as long as you don't pass an album name to add() which is longer than 51 characters. If you do, you'll get very weird output, and possibly a crash.
To guard against this, you should use a length-limited copy - for example:
void add(char *name,int id,int copies)
{
/* Pointer to next item */
struct list *newAlbum;
newAlbum = malloc(sizeof *newAlbum);
if (newAlbum) {
snprintf(newAlbum->name, sizeof newAlbum->name, "%s", name); // Set album name
newAlbum->id = id;
newAlbum->copies = copies;
newAlbum->pNext = pFirst;
pFirst = newAlbum;
}
}
(note that sizeof *newAlbum is a little better than sizeof(struct list), since the former is "obviously correct" when reading the line - it will still be corret if the type of newAlbum is ever changed).
The only thing I can see wrong here is that you don't check the length of name. You should use:
strncpy(newAlbum->name, 52, name);
This will prevent overrunning the name buffer.

Resources