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?
Related
I was making a linked list in C, then a query raised in my mind that (read the title above)
struct node
{
int data;
char age;
} temp;
// versus
struct node
{
int data;
struct node* next;
} *temp;
A struct like node cannot contain itself. If this were allowed, each struct node variable would be infinitely sized.
struct node* next; is a pointer to a struct node value. A pointer has a known, finite size and thus a struct can contain a pointer to another value of the same type. By having a pointer to a next struct node you are creating a linked list. This pointer can also be NULL which allows your list to have an end.
// Linked list implementation in C
#include <stdio.h>
#include <stdlib.h>
// Creating a node
struct node {
int value;
struct node *next; //What is this, what are we doing here?
};
// print the linked list value
void printLinkedlist(struct node *p) {
while (p != NULL) {
printf("%d ", p->value);
p = p->next;
}
}
int main() {
// Initialize nodes
struct node *head;
struct node *one = NULL;
struct node *two = NULL;
struct node *three = NULL;
// Allocate memory
one = malloc(sizeof(struct node));
two = malloc(sizeof(struct node));
three = malloc(sizeof(struct node));
// Assign value values
one->value = 1;
two->value = 2;
three->value = 3;
// Connect nodes
one->next = two;
two->next = three;
three->next = NULL;
// printing node-value
head = one;
printLinkedlist(head);
}
I want to ask what are we doing here with this line of code?
it's in the creating a node part of the code (top).
struct node *next;
Are we assigning a pointer type struct variable for the sturct node but its inside of the same struct, assigning a variable named *next inside the same struct? But that isn't allowed, right?
we can either declare the variable out side the } and between ; or in the main()
function part of the code only, Isn't it?
Like
main()
{
struct node *next;
}
Again, then I came across a post mentioning it as a pointer to the structure itself, can anyone explaine how can we do this inside the same struct?
The next member points to another instance of struct node. Graphically, we usually represent it like this:
+–––––––+––––––+ +–––––––+––––––+
| value | next |––––> | value | next |
+–––––––+––––––+ +–––––––+––––––+
A struct type cannot contain an instance of itself - we can’t create a type like
struct node {
int value;
struct node next;
};
for two reasons:
The type definition isn’t complete until the closing }, and you cannot create an instance of an incomplete type;
The type would require infinite storage (struct node contains a member next of type struct node which contains a member next of type struct node which contains a member next of type struct node...);
However, we can declare next as a pointer to struct node, since we can create pointers to incomplete types. The size and representation of a pointer is independent of the size and representation of the type it points to.
What it means
The line struct node *next; is read as "next is a pointer to another struct node".
This is just a recursive structure declaration (definition):
struct node {
int value;
struct node *next; //What is this, what are we doing here?
};
It says a node consist of two parts:
an integer value
a pointer to another node.
The wiki article on linked lists has a nice visualization showing how one node points to another (or to NULL to end the chain).
How does it work?
As you noted, the interesting part is how the declaration can include a reference back to itself. The compiler handles this in two steps:
It sizes the struct as consisting of an int and a pointer (they're all the same size regardless of what they are pointing to).
Later it type checks the assignment and generates the appropriate assembly. When you write one->value = 1;, it makes sure the 1 is an integer and generates code to move 1 to the integer slot. And when your write one->next = two;, it verified that two is a pointer to a node and generates code to move that pointer to the second slot for the struct node pointer.
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
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.
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);