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.
Related
I'm trying to implement a BubbleSort-Algorithm into my C-Program to sort elements of structures (for example by "name"-elements) inside of a doubly linked list, containing entries of games I like.
When I'm trying to assign an element to another of the same type, I get this error message:
[Error] assignment to expression with array type
Here is the relevant part of my code:
typedef struct game {
char name[50];
float price;
int release;
char genre[30];
struct game *next; /*points to the next structure and to NULL if it's the last one*/
struct game *prev; /*points to the previous structure and to NULL if it's the first one*/
}game;
typedef struct {
struct game *first; /*points to the first element*/
struct game *now; /*points to the element currently viewed*/
struct game *last; /*points to the last element*/
}s_field;
void swap(s_field *lib) {
char *tempName;
tempName = lib->now->name;
lib->now->name = lib->now->next->name; /*This is the line where I first get the error*/
lib->now->next->name = tempName;
/*There are assignments like those above for every other variable here*/
}
swap(s_field *lib) is being executed within the main-function.
Is there a way to circumvent this problem? For example by some sort of typecast?
I'm confused as to why I am getting an incompatible pointer type warning from my code. My debugger says that the issue is with the line
nodeToInsert->next = *head;
The particular line is a part of the function
user_t *moveNameToHead();
I don't know why this error is occurring since both pointers of of type user_t. This is the relevant code for the issue
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NAME_LENGTH 20
typedef struct user {
char name[NAME_LENGTH];
int numOfFriends;
char nameOfFriend[NAME_LENGTH];
struct node *next; //used for our linked list
} user_t;
//prototypes of functions to be used
void addQueryType();
user_t *createNewNameNode(char *name);
user_t *moveNameToHead();
int main() {
/// some code that eventually calls addQueryType ///
}
void addQueryType() {
char nameOfPersonA[NAME_LENGTH], nameOfPersonB[NAME_LENGTH];
//record names user enters
scanf("%s", nameOfPersonA);
scanf("%s", nameOfPersonB);
user_t *head, *temporary;
temporary = createNewNameNode(nameOfPersonA);
moveNameToHead(&head, temporary);
temporary = createNewNameNode(nameOfPersonB);
moveNameToHead(&head, temporary);
}
//will create nodes for us on a needs basis
user_t *createNewNameNode(char *name) {
user_t *node = malloc(sizeof(user_t));
strcpy(node->name, name);
node->next = NULL;
return node;
}
//moves newly added name to head of the linked list
user_t *moveNameToHead(user_t **head, user_t *nodeToInsert) {
nodeToInsert->next = *head;
*head = nodeToInsert;
return nodeToInsert;
}
I'm trying to create a linked list with the user names. The names are turned into nodes of the list and then are then fed into a function that turns the most recent name into the head of the list. The issue is I don't know why I'm getting the incompatible pointer type warning.
I've tried changing *head to a char type thinking that maybe that would have something to do with it since the items in the list are names, but that returned the same error along with others.
Any help with this issue would be greatly appreciated.
Correct your typo:
typedef struct user {
char name[NAME_LENGTH];
int numOfFriends;
char nameOfFriend[NAME_LENGTH];
struct user *next; //used for our linked list
} user_t;
Then it works
The compiler is throwing you a warning because, user_t::next and user_t *head are defined as different types.
head is of type user_t * while user_t::next is of type struct node *. Which seems to be an undefined struct. Consider changing user_t::next to be defined as type struct user *.
Example:
typedef struct user {
char name[NAME_LENGTH];
int numOfFriends;
char nameOfFriend[NAME_LENGTH];
struct user *next; //used for our linked list
} user_t;
#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;
}
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
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);