Writing to a linked lists with nested structs - c

I am trying to write a function that can read some info from a file into a node in a doubly linked list. The format for the each nodes data is as follows.
struct(named record)
artist
album
song
genre
songLength(This is another struct that contains mins and secs)
playcount
rating
void load(FILE *file, Node *head)
{
char tempArtist='\0', tempAlbum='\0', tempTitle='\0', tempGenre='\0'
,tempSpace='\0',tempMins='\0',tempSecs='\0';
SongLength *tempLength=NULL;
int tempPlay=0, tempRating=0,test=0;
tempLength = (SongLength*)malloc(sizeof(SongLength));
fscanf(file,"%s",&tempArtist);
fscanf(file,"%s",&tempAlbum);
fscanf(file,"%s",&tempTitle);
fscanf(file,"%s",&tempGenre);
fscanf(file,"%s",&tempMins);
fscanf(file,"%s",&tempSecs);
fscanf(file,"%s",&tempPlay);
fscanf(file,"%s",&tempRating);
fscanf(file,"%s",&tempSpace);
tempLength->mins=tempMins;
tempLength->secs=tempSecs;
head->data->album=tempAlbum; // breaks here
head->data->artist=tempArtist;
head->data->genre=tempGenre;
head->data->song=tempTitle;
head->data->length=tempLength;
head->data->played=tempPlay;
head->data->rating=tempRating;
}
This is my current load function. When attempting to store these values in to nodes data I get an access violation.
Here are my structs for easy reproduction
typedef struct songlength
{
int mins;
int secs;
}SongLength;
typedef struct record
{
char artist;
char album;
char song;
char genre;
struct songlength *length;
int played;
int rating;
}Record;
typedef struct node
{
struct node *pPrev;
struct node *pNext;
struct record *data;
}Node;
makeNode
Node *makeNode(Record *newData)
{
Node *temp = NULL;
temp=(Node*)malloc(sizeof(Node));
temp->data=newData;
temp->pNext=NULL;
return temp;
}
If any confusion arises just let me know!
Also this is my first experience with dynamic memory so be gentle :P
Thanks!

These lines are not right.
fscanf(file,"%s",&tempArtist);
fscanf(file,"%s",&tempAlbum);
fscanf(file,"%s",&tempTitle);
fscanf(file,"%s",&tempGenre);
fscanf(file,"%s",&tempMins);
fscanf(file,"%s",&tempSecs);
fscanf(file,"%s",&tempPlay);
fscanf(file,"%s",&tempRating);
fscanf(file,"%s",&tempSpace);
They will definitely lead to undefined behavior because of the way the variables are defined.
You cannot expect
char c = '\0';
fscanf(file, "%s", &c);
to work. There isn't enough memory at &c to read a string. You need something like:
char s[100]; // Or some size that is large enough to hold the data
// you are about to read.
fscanf(file, "%99s", s); // Make sure that you don't read more than 99
// characters. Leave at least one character
// for the terminating null character.
I hope that gives you enough clues on how to change your variables.

You did not assign memory for the variable tempLength to point to.
Add this before accessing the elements
SongLength *tempLength = malloc(sizeof(struct(SongLength));
EDIT
I'm just giving an overall idea how to allocate and use nested structs for your case
Node *head;
Record *r=malloc(sizeof(struct record));
SongLength *s=malloc(sizeof(struct songlength));
r->length=s;//<----- 1
r->length->mins=10;//Now you can assign values
head=malloc(sizeof(struct node));
head->pPrev=NULL;
head->pNext=NULL;
head->data=r;//<--- The length member inside record is already assigned memory in 1
head->data->artist='c';
head->data->length->mins=10;//assign

Related

Take data from a file and add it to the Linked List in C

#include<string.h>
#include<stdio.h>
struct Friend{
char name[50];
char surname[50];
char gender;
char date[50];
struct Friend * next;
};
struct Friend* initialize(char *);
int main(){
char name[100];
printf("ENter the name of the file\n")
gets(name);
struct Friend * head;
head=initialze(name);
}
struct Friend * initialize(char *name){
FILE * ffile;
ffile=fopen(name,"r");
if(ffile==NULL)
exit(1);
}
Here are my Function initizaliations in C. I need to take and open a file (example of how the file looks is below), and make a LINKED LIST which holds the NAME, SURNAME, GENDER AND DATE OF BIRTH of each person, and return the (HEAD pointer) start address of the linked list. I have finished the task by taking one character at a time, by having 3 nested while loops. But as you might have guessed this is a very inefficient solution.
The name of the file doesn't matter since I am prompting the used to write it. But here is how the FILE LOOKS LIKE
John;Lenny;M;13/01/1978;
Josh;Bush;M;15/05/1989;
Anjelica;Victoria;F;20/10/1990;
So as you see we have a semicolon(;) after each element
I would approach this a bit different.
you can either read the entire file to a buffer or read it and store after every time you encounter "\n"
Then you have to have a method that creates a node of the desired structure and fill in the data from the current line you've just read.
For example:
void create(Friend* Head)
{
struct Friend *new_node = malloc(sizeof(Friend));
new_node->whatever = whatever;
Head->Next = new_node;
}

Data becomes modified during printf

After I read in some data from a file, an assign it to a struct type record within a node the data matches that of the file. After I leave the read function and go back in to main the data still remains the same. But when I attempt to print it, it becomes a jumbled mess.
Load Function
void load(FILE *file, Node *head)
{
char tempArtist[30]={'\0'}, tempAlbum[30]={'\0'}, tempTitle[30]={'\0'}, tempGenre[30]={'\0'},tempSpace='\0';
SongLength *tempLength=NULL;
int tempPlay=0, tempRating=0, tempMins=0, tempSecs=0;
tempLength = (SongLength*)malloc(sizeof(SongLength));
fscanf(file,"%s",&tempArtist);
fscanf(file,"%s",&tempAlbum);
fscanf(file,"%s",&tempTitle);
fscanf(file,"%s",&tempGenre);
fscanf(file,"%s",&tempMins);
fscanf(file,"%s",&tempSecs);
fscanf(file,"%s",&tempPlay);
fscanf(file,"%s",&tempRating);
fscanf(file,"%c",&tempSpace);
tempLength->mins=&tempMins;
tempLength->secs=&tempSecs;
head->data->album=tempAlbum;
head->data->artist=tempArtist;
head->data->genre=tempGenre;
head->data->song=tempTitle;
head->data->length=tempLength;
head->data->played=tempPlay;
head->data->rating=tempRating;
}
Print Test Function
int main(void)
{
FILE *loadFile = NULL;
Node *head=NULL;
head=(Node*)malloc(sizeof(Node));
head->data=(Record*)malloc(sizeof(Record));
head->data->length=(SongLength*)malloc(sizeof(SongLength));
loadFile=fopen("records.txt","r");
load(loadFile,head);
head->data->artist; // artist matches the name in load file (aka snoop)
printf("%s", head->data->artist); // When trying to print here it prints a smiley face
}
Extra info for easy replication
typedef struct songlength
{
int *mins;
int *secs;
}SongLength;
typedef struct record
{
char *artist;
char *album;
char *song;
char *genre;
struct songlength *length;
int played;
int rating;
}Record;
typedef struct node
{
struct node *pPrev;
struct record *data;
struct node *pNext;
}Node;
File Data Format
snoop
heartbeat
swiggity
rap
03
10
25
4
You have undefined behavior because you assign pointers to local arrays to the head structure.
For example, the array tempArtist will go out of scope once the function load returns, so any pointers pointing to that array (like head->artist) will be stray pointers, and derefeencing those pointer will lead to said undefined behavior.

Access data stored in struct within Doubly Linked List?

I'm not sure how specific I have to be but I'll give the breakdown best I can. I'm taking a typedef struct:
typedef struct {
char name[21];
int life;
} pcb_t;
inputting values for the name & life, then storing it in a doubly linked-list.
the linked-list structs in the header file are:
typedef struct list_node {
void *data;
struct list_node *next;
struct list_node *prev;
} List_node_t;
typedef struct {
List_node_t *head;
List_node_t *tail;
} List_t;
In my main I have the first struct variables initialized as:
char name[BUF_MAX];
int life;
pcb_t *pcb;
The input is all correct and the pcb struct is stored as a new node in the list. I tried to run a simple loop after the initial input to print out the Name & Lifetime values for each of the pcb structs. The loop I used is this:
void *context = NULL;
void *data;
while( List_next_node( &the_list, &context, &data) && (data != NULL))
{
printf("Name: %s\n", (char *)data);
printf("Lifetime: %d\n", (int )data);
}
Where the List_next_node function transverses the list. the_list is the list, context is what keeps track of where we are in the list, and data is the data.
I'm not sure how to access the information I want as my while loop correctly prints out the Name of the pcb struct, but the lifetime is not.
Lists, doubly linked or otherwise, are a complete red herring, here. The issues are (1) accessing struct members, which hopefully is trivial; and (2) doing that when all you have is a void *, which is possibly a little less intuitive.
This is the simplest way:
void *data;
while( List_next_node( &the_list, &context, &data) && (data != NULL))
{
pcb_t * current_data = data;
printf("Name: %s\n", current_data->name);
printf("Lifetime: %d\n", current_data->life);
}
The only reason your current code "works" for printing out the name is because name is the first element of your struct, and so the address of name happens to be the same as the address of the whole struct, so when you cast the address of the struct to char * you get the result you're expecting, even though you're not really getting there the right way.
As ojblass's answer shows, you can do it with a cast and avoid the use of a temporary variable, but I think a temporary variable makes things a lot clearer.
printf("Lifetime: %d\n", ( (pcb_t *) data) ->life);

structures for multilevel feedback queue initialization

Helllo,
I am trying to build a multilevel feedback queue and im having an issue with accessing the data structures.
struct str1
{
` int time;
int Id;
int Size;
struct str1 *next;
};
struct mlfq
{
int quantum;
int timereached;
struct mystruct p;
};
struct str1 *front; //read from the file and stored.
struct mlfq *ml;
What I want to do is link the "mlfq" to the other "front" queue.
In my insert function, I have allocated memory
struct mlfq *ptr;
struct str1 *temp;
ptr = malloc(sizeof(struct mlgq)
temp=malloc(sizeof(struct str1));
ptr->p = front;
getting error: INCOMPATIBLE TYPES IN ASSIGNMENT.
Now front is loaded and im trying to get the contents of queue structure "front" to link to it.
Can anyone tellme what;s going on?
In
ptr->p = front;
ptr->p is of type struct str1 or struct mystruct (you seem to be mixing them up), while front is of type struct str1 * or struct mystruct *. You're trying to assign a pointer to a variable of a non-pointer type. You need to dereference front for the assignment to be correct. A statement that compiles properly would be
ptr->p = *front;
I once had implemented Multilevel feed back queue scheduling algorithm(which was a creation of my own).I had made 3 queues, first one with time quantum 10ms(FCFS),second one with time quantum 40ms(FCFS) and the third and the last one with just First come first serve Algo.

Why does my list only ever return the element most recently added?

Greetings again,
I have this problem again on C but now using struct.
Having this structure of student
struct student {
char *name;
int age;
}
I wanted to a list where I could add a number of Student and can also view all of its elements. Here's the code I have done so far.
#include<stdio.h>
#include<stdlib.h>
// struct student ...
void add(student **list, char* name, int age) {
student* temp = (student *)malloc(sizeof(student));
temp->name = name
temp->age = age;
*list = temp;
*(list++) = (student *)malloc(sizeof(student));
}
void view(student **list) {
student* data = *list;
while(data != '\0') { printf("%s%i", data->name, data->age); *(data++); }
}
main() {
student* list = (student *)malloc(sizeof(student));
char* name = (char *)malloc(sizeof(char));
int age=0;
// inputs for name and age
// do-while(option != EXIT_VALUE);
// inside do-while are the following below
add(&list, name, age);
view(&list);
}
I only get the newest student upon the view method.
It makes sense, since you are allocation space for 1 single student structure:
student* list = (student *)malloc(sizeof(student));
You should do something like:
int list_size = 20;
student* list = (student *)malloc(sizeof(student) * list_size);
The name variable suffers from the same problem.
A dynamic linked list should have a reference to the next and previous elements. You'll have to change your program to work with:
struct student {
char *name;
int age;
struct student* next;
struct student* previous;
}
Also you are doing *(data++) which isn't necessary. data++ is just fine. You really shouldn't be needing the double pointers everywhere, it only complicates things. For allocation, fine (if you think that's the best way), but for passing to other functions that only READ the pointer, there's no need.
view expects list to be an array (null-terminated) of pointers to student. However, you allocate it in main as a pointer to a single student. Then, you just reassign that student pointer every time you call add. As Chris said, it would probably be fine (and simpler) just to have a list of students.
If you want to implement the list as an array, you need a strategy to re-allocate the list when it gets larger than the initial array size. A typical strategy is to choose an arbitrary size that will handle most cases without wasting tons of memory, and then double that amount when the bound is reached. So, say you start with an 8-element list. When you add the 9th element, it would reallocate the array to a 16-element list.
The other strategy is to use a linked list, where you add a struct pointer (typically named "next") to your structure and use that to iterate through your list. This makes allocation and traversal a lot simpler, although list retrieval becomes an O(n) operation instead of an O(1) operation, which means it takes longer to get a particular element from the list as the list gets larger.
You have two options.
Create linked list and you will be able to insert as many students you want. (each student has also pointer on next student if any else it is NULL)
Create array of pointers on students as suggested by karlphillip, but method to add new student will need to implement position searching or storing this postion. (you have to figure out where should you store pointer that points on student)
I only get the newest student upon the view method.
void add(student **list, char* name, int age) {
student* temp = (student *)malloc(sizeof(student));
temp->name = name
temp->age = age;
*list = temp;
*(list++) = (student *)malloc(sizeof(student));
}
Notice that you are making list point to the newly allocated memory location. The previous value it was pointing to is lost and also causes memory leak. And so only you are getting the last entry. You need to implement a linked list like structure.
struct student {
char *name;
int age;
struct student *next ;
}
// ....
void add(student **list, char* name, int age) {
// Make sure that every new location is saved in next
// And also the next time when you call this method, it should be
// location of "next" pointing to being passed as parameter.
}
int main()
{
student *list = malloc(sizeof(student)); // No need to type cast malloc
student *preserveHeadNode = list ;
add(&list, name, age);
// .. While viewing pass the "preserveHeadNode" and run the loop until
// student::next == NULL
}

Resources