I'm quite newbie in C and now I'm trying to implement basic generic linked list with 3 elements, each element will contain a different datatype value — int, char and double.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
struct node
{
void* data;
struct node* next;
};
struct node* BuildOneTwoThree()
{
struct node* head = NULL;
struct node* second = NULL;
struct node* third = NULL;
head = (struct node*)malloc(sizeof(struct node));
second = (struct node*)malloc(sizeof(struct node));
third = (struct node*)malloc(sizeof(struct node));
head->data = (int*)malloc(sizeof(int));
(int*)(head->data) = 2;
head->next = second;
second->data = (char*)malloc(sizeof(char));
(char*)second->data = 'b';
second->next = third;
third->data = (double*)malloc(sizeof(double));
(double*)third->data = 5.6;
third->next = NULL;
return head;
}
int main(void)
{
struct node* lst = BuildOneTwoThree();
printf("%d\n", lst->data);
printf("%c\n", lst->next->data);
printf("%.2f\n", lst->next->next->data);
return 0;
}
I have no problem with the first two elements, but when I try to assign a value of type double to the third element I get an error:
can not convert from double to double *
My questions:
What is the reason for this error?
Why don't I get the same error in case of int or char?
How to assign a double value to the data field of the third element?
The problem string is (double*)third->data = 5.6;.
In your "working" examples, you're calling malloc to get a pointer to some newly-allocated space, and then immediately throwing that pointer away and replacing the pointer value with your integer or character value. That works more or less by accident because in most C implementations a pointer cell can hold an integer or char value, though you should be getting warnings. If you actually tried to dereference the data pointer after those assignments, you would probably get a crash and core dump.
You want to put the values at the place pointed to by the pointer, not in the pointer itself. Which means you need an extra *:
*((double *)third->data) = 5.6;
The * in the (double *) typecast is part of the type name - "pointer to double". The cast says "take the value of third->data and interpret it as a pointer to double". The result is still a pointer, so when you assign to that, you are changing where the pointer points (and probably making it point somewhere meaningless). Instead, you want to assign a value to the place it already points, which is what the outer * does.
However, if you're only storing basic types like int, char, and double, you don't need to go through a pointer (and worry about the attendant memory management). You can just use a union:
struct node
{
struct node *next;
union {
char c;
int i;
double d;
} data;
}
Then you would do e.g.
head->data.i = 2;
second->data.c = 'b';
third->data.d = 5.6;
You are casting the pointer, but you need to derefernce it for the assignment, the assignment worked for the first two since the int and char were casted to pointers, it should be:
*((int*)(head->data)) = 2;
*((char*)(second->data)) = 'b';
*((double*)(third->data)) = 5.6;
Anyway, there should be warning for such a cast in first place.
You can't assign the value to the pointer, you have to assign it to the object pointed (in the last case, a double - you only have space for one double).
So:
...
head->data = (int*)malloc(sizeof(int));
((int*)(head->data))[0] = 2;
head->next = second;
second->data = (char*)malloc(sizeof(char));
((char*)second->data)[0] = 'b';
second->next = third;
third->data = (double*)malloc(2 * sizeof(double));
((double*)third->data)[0] = 5.6;
((double*)third->data)[1] = 3.1415;
// We only allocated space for 2 doubles, so this line here would cause a crash
// (or anyway, a data corruption)
// ((double*)third->data)[2] = 666;
third->next = NULL;
return head;
}
int main(void)
{
struct node* lst = BuildOneTwoThree();
printf("%d\n", ((int *)lst->data)[0]);
printf("%c\n", ((char *)lst->next->data)[0]);
printf("%.2f\n", ((double *)lst->next->next->data)[0]);
printf("%.2f\n", ((double *)lst->next->next->data)[1]);
...
returns:
2
b
5.60
3.14
BTW: with full warnings enabled, the compiler should have warned you that the first two assignments were risky (GCC considers them errors) and the third one unallowed (can't convert from a double to a pointer)
One more thing: when you use a struct payload this way, you have to consider that the data type that you actually stored in the payload itself is lost. So you can't, by inspecting an instance of your linked list, determine whether it is a char, an integer or a double. Worse, even checking the value might not be allowed and crash the program (suppose you stored a single byte, but try to read four or eight).
So you ought to also store an extra field in your structure holding an indicator (an enum maybe) of the original data type:
typedef enum
{
TYPE_IS_CHAR,
TYPE_IS_INT,
TYPE_IS_FLOAT,
TYPE_IS_DOUBLE,
...
} mytype_t;
struct node
{
mytype_t type;
void *data;
struct node *next;
}
Related
List.c
int const LIST_SIZE = 100;
typedef struct node {
void *item;
} Node;
typedef struct list {
Node *currentItem;
Node *items[LIST_SIZE];
} LIST;
main.c
#include <stdlib.h>
#include <printf.h>
#include "List.h"
LIST *ListCreate();
int main() {
LIST *newList = ListCreate();
Node *newNode = malloc(sizeof(Node));
newList->currentItem = newNode;
newNode->item = (int *)200;
printf("%d", *((int *)newNode));
}
LIST *ListCreate() {
LIST *newList = malloc(sizeof(LIST));
return newList;
}
My question is:
In main.c, I use the printf statement to access the item in the newNode. According to my understanding the proper call should be:
printf("%d", *((int *)newNode->item));
However, I get a segmentation fault when using this. Could anyone please explain me why this doesn't work and the other one works?
Thanks.
(int*)200 tells the compiler to take the number 200 and pretend it's the address of an int. However, it's not actually a valid address of an int, so you can't dereference it (i.e. you can't use *(int*)newNode->item to get the int at that address).
All you want to do is tell the compiler to take the "address" and treat it as a number again, which you can do using:
printf("%d", (int)newNode->item);
The (int) cast undoes the (int*) cast from before.
Side note: using (int*) here is slightly unusual; there's no reason to use it instead of (void*).
You're storing 200 (which isn't a pointer value) in the pointer variable, and then you deference the variable as a pointer even though it doesn't actually contains a pointer value.
General pattern for some type type:
Node* node = malloc(sizeof(Node));
node->item = malloc(sizeof(type));
*((type*)node->item) = ...;
type val = *((type*)node->item);
free(node->item);
free(node);
So, to store an int, it would be
Node* node = malloc(sizeof(Node));
node->item = malloc(sizeof(int));
*((int*)node->item) = 200;
printf("%d\n", *((int*)node->item));
free(node->item);
free(node);
Now, pointers can be used to store integers, so you could save an allocation in this particular case by using some trickery. This is a more advanced solution.
Node* node = malloc(sizeof(Node));
node->item = (void*)200; // Store the number in a pointer variable.
printf("%d\n", (int)node->item); // Treat the pointer variable as an `int`.
free(node);
Making a slight change to the main() lets take a look at this application run using Visual Studio 2013 in debug mode.
The modified main() is as follows:
int main() {
LIST *newList = ListCreate();
Node *newNode = malloc(sizeof(Node));
newList->currentItem = newNode;
newNode->item = (int *)200; // assign the value 200 to the pointer item
printf("*((int *)newNode) %d\n", *((int *)newNode)); // works
printf("((int)newNode->item) %d\n", ((int)newNode->item)); // works
printf("*((int *)newNode->item) %d\n", *((int *)newNode->item)); // access violation exception
}
When this console application is run, the window displayed contains two lines of output:
*((int *)newNode) 200
((int)newNode->item) 200
In the debugger, when single stepping through the function main() an access violation exception is thrown on the indicated line. The actual text of the access violation is:
First-chance exception at 0x010E1BAF in ConsoleApplication1.exe: 0xC0000005: Access violation reading location 0x000000C8.
Unhandled exception at 0x010E1BAF in ConsoleApplication1.exe: 0xC0000005: Access violation reading location 0x000000C8.
The location being read, 0x000000C8, is the decimal number 200 and when an attempt is made to dereference the pointer item as an int pointer containing the value of 200, the memory location of 200 is not valid for this application running under Windows 10 in user mode.
*((int *)newNode) means to treat the value of the variable newNode as a pointer to an int and to then fetch the value at that address. This works because newNode contains an address this application can access.
(int)newNode->item means to treat the value of the variable newNode->item as an int and to fetch the value of that variable. The variable is not treated as a pointer but as a variable containing an int.
*((int *)newNode->item) means to to treat the value of the variable newNode->item as a pointer to an int and to then fetch the value at that address. This doesn't work because the value of the variable newNode->item, a value of 200, is not an address this application can access so an access exception is thrown when the attempt is made.
According to my understanding the proper call should be:
printf("%d", *((int *)newNode->item));
That is true only from a syntactic point of view. But it is wrong because you are not using pointers correctly.
newNode->item = (int *)200;
Not sure what you were expecting that line to do. Casting 200 to an int* does not give you a valid pointer.
*((int *)newNode->item
only dereferences the value 200 pretending to be a valid pointer. This causes undefined behavior.
You can use:
// Allocate memory for newNode->item
newNode->item = malloc(sizeof(int));
// Set the value
*((int *)newNode->item) = 200;
// Print the value
printf("%d", *((int *)newNode->item));
Unless you wish to store other kinds of object in a node, I suggest using:
typedef struct node {
int item;
} Node;
and then your code can be a little bit simpler.
// Set the value
*newNode->item = 200;
// Print the value
printf("%d", newNode->item);
I have a struct:
struct structname
{
structname** link;
int total;
}
I want to link structname1 to structname2. What I did was:
int *ptr = &structname2;
structname1 -> link = &ptr;
Then I tried to access the link for structname1 which is structname2:
structname *test = structname1 -> link;
Is this the correct way to do it? When I tried to print out, some unknown symbols printed. Can someone help me with this? Thanks.
You have to do in the below way.
struct structname structname1, structname2; //define two structures structname1 and structname2 of type structname.
struct structname * ptr; // ptr is a pointer to struct of type structname.
struct structname ** ptr2 // ptr2 is a double pointer to struct of type structname.
ptr = &structname2; // ptr points to structname2
ptr2 = &ptr; // ptr2 points to ptr and ptr points to structname2;
structname1.link = ptr2; // now link is a double pointer to structname2.
Let me correct if i'm wrong or missing
You have a couple of things wrong in your code. First, you got the type for ptr wrong: it should be struct structname ** instead of int *.
But if you're trying to do a linked list, you don't need the double indirection level at all. This is most likely what you want:
struct structname
{
struct structname *link;
int total;
}
With that, linking structname1 with structname2 is then as simple as (assuming structname1 and structname2 are of type struct structname):
struct structname *ptr = &structname2;
structname1.link = ptr;
If structname1 and structname2 are of type struct structname *, then you need this instead:
struct structname *ptr = structname2;
structname1->link = ptr;
You could also drop the intermediate variable ptr, it's not of much use here.
struct node {
struct node *next;
int cargo;
}
struct node *current, *last, *next;
unsigned char i;
current = (struct node*)(calloc(sizeof(struct node)));
for (last = current, unsigned char i = 5; i--;) {
next = (struct node*)(calloc(sizeof(struct node)));
next->cargo = i;
last->next = next;
}
The above code is a very easy linked list. Note that I changed a couple of things compared to your code. I create the objects using calloc, that means that the objects will be allocated on the heap instead of the stack. This also doesn't require you to have explicit names for every element, a.k.a. node in the linked list. It also means it won't be destroyed when you leve the scope of the names. Of course you will need to free all the nodes later, when you don't need the list anymore.
Then you don't need a pointer to a pointer in the node, a simple pointer is sufficient. In your main program you should also use an appropriate pointer. Even though, all pointers are the same size and can be cast into each other, you should - whenever possible - usde the right type.
Here I create another 5 nodes in a loop to demonstrate how 'flexible this approach is'.
If you want to do a circular linked list, that is quite easy as well. Simply append these line:
next->next = current;
So I'm trying to add a card to a player's hand... and the value of the card will only be passed back to the main function if I use a double pointer for the top and last cards. But last->pt can't translate to temp, how do I fix this?
typedef struct card_s
{
char suit[9];
int value;
struct card_s *pt;
} card;
void deal_card(card **top, card **last, card dealt)
{
card *temp;
temp = (card*)malloc(sizeof(card));
strcpy(temp->suit, dealt.suit);
temp->value = dealt.value;
if(*top == NULL)
*top = temp;
else
*last->pt = temp; //FIX ME - something is going wrong at this point
*last = temp;
last->pt = NULL; //FIX ME - same problem as above
}
The problem seems to be operator precedence, so using parentheses should resolve it:
(*last)->pt = temp;
The way it was written originally, it was treating last as a (single) pointer, and trying to dereference member pt. Instead, you want to dereference last, and then access member pt of the resulting pointer.
Since pointers to structures are common, and the parentheses in the example above are a nuisance, there's another structure selection operator which works on pointers to structures. If p is a pointer to a structure and m is a member of that structure, then
p->m
selects that member of the pointed-to structure. The expression p->m is therefore exactly equivalent to
(*p).m
You on the other hand are using some vague combination. Use either format.
E.g. last->pt or (*last).pt
Also these lines contain asterisks that don't belong there I believe:
if(*top == NULL)
*top = temp;
else
*last->pt = temp; //FIX ME - something is going wrong at this point
*last = temp;
All together, this should work:
if(top == NULL)
top = temp;
else
last->pt = temp;
last = temp;
(Assuming you want to change the address the pointer is pointing to. If you use a asterisk in front of it you are comparing/assigning with the actual value the pointer is pointing to.
This may be a stupid question, and I see similar questions been asked, but I dont get the answers given. why does the following code produce:
error: incompatible types when assigning to type ‘node_t’ from type ‘struct node_t *’
node_t list_array[10];
typedef struct node
{
int value;
struct node *next;
struct node *prev;
} node_t;
node_t* create_node(void)
{
node_t *np;
np->next = NULL;
np->prev = NULL;
np->value = rand() % 10;
return np;
}
int main(void)
{
int i;
for(i = 0; i < 10; i++)
{
list_array[i] = create_node();
}
return 0;
}
Make the array into an array of pointers to fix the error, since create_node returns a pointer:
node_t *list_array[10];
Note you're not allocating any memory in create_node so using np is illegal. Try:
node_t *np = malloc(sizeof *np);
I want to make an array of node_t structs
In that case you could leave the node_t list_array[10] and:
Pass &list_array[i] as an argument to the function
Have the function return a node_t instead of a node_t *
Because one is a structure and the other is a pointer to the structure.
The create_node() function returns a pointer to a node (which you really should malloc() in that function, by the way) and you try to assign it to an actual structure in the array.
You can solve it by simply changing your declaration to:
node_t *list_array[10];
so that it's an array of pointers rather than an array of structures.
Because create_node() returns a pointer, but list_array[i] is an actual instance. You can't assign a pointer over an instance, they're completely different.
The solution is typically to represent each node as a pointer, which requires list_array to be an array of pointers:
node_t *list_array[10];
Then the assigment makes sense, and the code will compile.
Note, however, that the code will not "work", since it's dereferencing a NULL pointer inside create_node(). It seems you forgot to call malloc():
node_t* create_node(void)
{
node_t *np;
if((np = malloc(sizeof *np)) != NULL)
{
np->next = NULL;
np->prev = NULL;
np->value = rand() % 10;
}
return np;
}
This is the classic "pointer vs. instance" confusion. Even more serious than your warning is:
node_t *np;
np->next = NULL;
which will compile, and then segfault.
The confusion arises because of a misunderstanding of what a pointer is. When compiled, a pointer is just a single number, like 140734799803888. This number is used just to locate the physical chunk of data. It's a memory address.
Pointers vs. instances are confusing, and one of the first conceptual challenges you encounter in programming. So here's an analogy:
If you've ever used a GPS, it will tell you where you are (pointer) but not what you are (data). Pointers work the same way. If someone wants to shake your hand, they wouldn't shake GPS coordinates (pointer)! They'd use the GPS coordinates to locate you, then physically visit you (data) and shake your hand. That's how pointers work.
So in your code above, you declare a pointer np, but don't give it any location to keep track of. Then, you ask "use the number in np to locate my data" (but you haven't set a number for np!) In particular, np->next asks to use the location np + someOffset (which is undefined!) to find your physical data (which is nowhere), and change it.
That's why you get a seg fault.
node_t list_array[10] should be node_t *list_array[10]
You have also, not malloced your node_t *np
node_t *np = malloc(sizeof(node_t));
For this program, I see no point to using dynamic storage duration (malloc). I would dispose of create_node in favour of memcpy, if you wish to keep all of your objects in static storage duration. For example,
#include <string.h>
typedef struct node
{
int value;
struct node *next;
struct node *prev;
} node_t;
int main(void) {
node_t list_array[10];
for (int i = 0; i < sizeof (list_array) / sizeof (*list_array); i++) {
memcpy(list_array + i,
&(node_t){ .value = rand() % 10,
.next = NULL,
.prev = NULL },
sizeof (*list_array));
}
return 0;
}
I wrote a quick generic linked list, simple stuff. But I have a bug and I cannot spot what it is complaining about. Pertinent code:
typedef struct _node {
void *data;
struct _node *next;
} node;
typedef struct _queue {
node *root;
node *last;
unsigned int length;
} queue;
node * find_node(void *data, int size, queue *q)
{
node *n;
for(n=q->root;n;n=n->next)
if(memcmp(data, n->data, size)==0)
return (n);
return (NULL);
}
Testing it:
queue q = {NULL, NULL, 0};
node *n;
int data[QUEUEMAX];
int i;
/* insert bunch of ints into queue */
for(i=0;i<QUEUEMAX;i++) {
data[i] = give_me_a_number();
n = alloc_node();
n->data = data[i];
insert_into(n, &q);
}
printf("list size = %d.\n", q.length);
/* print out, make sure they're there */
for(n=q.root;n;n=n->next)
printf("data = %d\n", (int)n->data); //*(int *)n->data didn't work, segfault?
/* find a specific node */
node *nd = find_node(&data[10], sizeof(int), &q);
/* remove it */
rm_node(nd, &q);
Running it:
$ ./test
list size = 256.
data = 10
data = 11
data = 12
data = 13
data = 14
data = 15
data = 16
... blah blah (256 lines)
Segmentation Fault
gdb says the problem is the memcmp() in find_node(). I think gcc is whining about the n->data being passed to memcmp(). Any ideas? Also, I was getting a segfault trying to do int x = *(int *)n->data but this seems valid to me, non?
In this code:
n->data = data[i];
You are currently setting the void* data pointer to be data[i] but you really want to set it to the address of data[i] so you need to do:
n->data = &data[i];
That is also why you got a segfault on your cast.
Segmentation Fault happens when you try to dereference NULL pointer. If you know the line where it happens verify that there no NULL there, example int x = *(int *)n->data will generate SEGFAULT if n is NULL or n->data is NULL
Assuming that your memory allocation functions are working, most likely n->data is NULL, and therefore you can't access it. Also, why are you passing the data array as &data[10]? Why not just use data since the identifier of an array is a pointer to its first location?
It looks like you are being inconsistent in whether your data is a pointer or if its a pointer thats being casted to an int. You are passing a int (since the pointer is basically a int cause of the cast).
memcpy naturally wants a void *, not an int.
So the solution really is to pass a pointer to your int in data and make everything else work with that.
Also, the memcmp call in find_node will sometimes compare too much data. You're using memcmp with the size of the data you're searching for. If the data in the current node is shorter than that, memcmp will go beyond it, into forbidden territory. (The test code you posted won't usually trip this bug, because most of the data fields have the same length.) You need to add a length field to each node, and use the minimum of both lengths in memcmp.
You're assigning an int variable
n->data = data[i];
To what it is supposed to be a pointer
typedef struct _node {
void *data;
struct _node *next;
} node;