I have a school project where I need to create a doubly linked list.
In one of my functions I want to create a new node and add a value to it but it doesn't work.
The function name and parameters can't be changed and I need to put this const declared string into a non-const declared string.
static struct node *make_node(const char *value)
{
struct node *node;
node = malloc(sizeof(node));
node->value = value;
return node;
}
I get the error message:
warning: assignment discards 'const' qualifier from pointer target
type [-Wdiscarded-qualifiers]
What your current code does is simply copy the address of one string (the given parameter) to the other (the struct data member). This is why the compiler generates the warning: the "parameter" value points to a string that cannot be changed; the "struct" value points to one that can be changed.
In order to copy the actual string data, you would first need to allocate enough memory to hold the string data, then copy the data to it:
static struct node *make_node(const char *value)
{
struct node *node;
node = malloc(sizeof(node));
node->value = malloc(strlen(value) + 1); // Add 1 to accommodate the nul-terminator
strcpy(node->value, value);
// node->value = value;
return node;
}
Alternatively, you can use the strdup function (this will do the allocation and copying for you):
node->value = strdup(value);
Feel free to ask for further clarification/explanation.
Related
// 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 have two functions in which one calls the other function and the title is the error I get. I am just wondering if there is a simple fix I am missing. Let me know if more information is needed. Thank you!
node createNode() {
newNode temp;//declare node
temp = (newNode)malloc(sizeof(struct node));//allocate memory
temp->next = NULL;//next point to null
return *temp;// return the new node
}
void enqueue(queue* q, customer* data) {
// Create a new LL node
struct node* temp = createNode(data);//error line
You want a return value of struct node*, so the return type should be struct node*.
Also naming the pointer to struct node as newNode looks very confusing (at least for me), so you shouldn't do that.
One more point is that casting results of malloc() family is considered as a bad practice.
Finally, you should check of malloc() succeeded.
struct node* createNode() { /* use proper return type */
/* use non-confusing type */
struct node* temp;//declare node
temp = malloc(sizeof(struct node));//allocate memory
if (temp == NULL) return temp; /* check if allocation succeeded */
temp->next = NULL;//next point to null
/* remove dereferencing */
return temp;// return the new node
}
void enqueue(queue* q, customer* data) {
// Create a new LL node
struct node* temp = createNode(data);//error line
Also it looks weird that the argument data is passed but ignored, but I won't fix this because I don't know how to fix.
I'm struggling to figure out how to pass a string into a function and then how to store it in struct via pointer. I want to create a linked list where each node contains a node name(string) and data(integer) representing the weight required to reach that node.
The structure representing the node is as follows:
struct ListNode
{
// The energy required to reach in this node
int data;
// The name of the node
char location[20];
// And the nodes along side this one
struct ListNode* next;
struct ListNode* prev;
};
The following function generates a node and sets its next and previous pointers:
// Allocate a new listNode with the provided value
struct ListNode* listNodeConstructor(int value, char *city)
{
struct ListNode* newNode;
// Reserve memory for a node
newNode = malloc(sizeof(struct ListNode));
// Set its values
newNode->data = value;
newNode->name = strdup(city); /* This is how I've tried to implement it but it causes an error */
newNode->next = NULL;
newNode->prev = NULL;
// And return it
return newNode;
}
If anyone can show me how to correctly store the string in the node struct, I would be eternally grateful.
strdup() copies a string to a newly malloced place in the heap and returns a pointer to the new string.
Note that you also need to free it.
The problem is, that the string you want to set is part of the structure and not just a pointer you can set.
You have two options:
Use strcpy(newNode->name,city); instead of newNode->name = strdup(city);. This copies the city string to newNode but you need to assure that city has a \0 until newNode->name overflows.
change name to be just a pointer and free it when you free the node. You can use strdup in that case. (Change char location[20]; to char *location;
You cant assign arrays. You can only assign scalar variables or structs or unions
struct ListNode
{
// The energy required to reach in this node
int data;
// The name of the node
char *name;
char name1[32];
struct ListNode* next;
struct ListNode* prev;
};
int foo(struct ListNode *node, const char *str)
{
node -> name = str; // but remember that it only assigns the
//reference and does not copy the string
/* OR */
node -> name = strdup(str); // but remember to free it
strcpy(node -> name1, str);
}
You are attempting to use strdup (3) which creates a copy of the string in a newly heap allocated space. You are therefore attempting to assign a pointer (which is the return of your strdup to a char array. As you already have allocated your string space in your structure, you should therefore use strcpy (3) instead in the following way: strcpy(newNode->name, city).
Also please note it is always a good practice to pass pointer parameters as const when you do not intend to modify them. This convention aims to improve readability and is very helpful when you want to debug your programs when they grow bigger.
I am tyring to use a generic linked list for my project. For reference, I am following this implementation made by David Muto. My aim is to parse user-information(user-name and other details) from a plain text file and load these into my linked-list.
typedef struct {
char *user_name;
char *password;
char *friends;
}user_info;
Here is the code-flow.
list users;
list_new(&users,sizeof(user_info*),free_users);
init_server(&users);
list_for_each(&users,iterate_users);
list_destroy(&users);
Parsing is done in init_server(). In it the user_info struct is allocated and reference to tokens are copied into it. After this I make a call to list_append().
list_append()
void list_append(list *list, void *element){
listNode *node = malloc(sizeof(listNode));
node->data = malloc(list->elementSize);
node->next=NULL;
memcpy(node->data,element,list->elementSize);
if(list->logicalLength == 0){
list->head = list->tail = node;
}else {
list->tail->next=node;
list->tail=node;
}
list->logicalLength++;
}
Problem
Only the username reference is present in all the elements in the list. Here are the values
of the element( structure reference passed to list_append()) and the head of the the list after the call returns.
(gdb) print *(user_info*)element
$31 = {username = 0x603270 "trudy", password =
0x603290"areyouthereyet",friends=0x6032b0 "bob;alice\n"}
(gdb) print *(user_info *)list->head->data
$36 = {username = 0x603270 "trudy", password = 0x0, friends = 0x0}
This:
sizeof(user_info*)
should be this:
sizeof(user_info)
You want the size of the struct itself, not the size of a pointer to it. Right now, your memcpy() call is not copying all the data as a result.
Similarly, listNode *node = malloc(sizeof(listNode)) should probably be listNode *node = malloc(sizeof(*node)) for the same reason. I'm assuming node->data = malloc(list->elementSize); will be correct once you're passing the right size to list_new().
What is the list->elementSize set to?
Another potential issue:
You're storing pointers to the memory where the strings are.
Suppose you parse a character string then store a pointer.
Later if the string is deallocated the pointer will be aimed at whatever gets placed there later. It will be very difficult to debug. Make sure your strings remain during the time you use your list.
Im not sure i got the concept of Linked List properly. What im trying to do is to create a linked list which receives the integer 6 as it's first "data". instead i get this access violation error when trying to write in the integer into the first node's data. is there something specific i missed here?
///////////////////////////////
typedef struct List_Node
{
int data;
struct List_Node* next;
}List_Node;
typedef struct List
{
List_Node* head;
}List;
////////////////////////////////
List* create_list();
void print_list(List_Node *x);
void add_to_node(List_Node *a,int val);
////////////////////////////////
void main()
{
List *a = create_list();
List_Node *ind = a->head;
printf("List:\n");
add_to_node(ind,6);
}
void print_list(List_Node *a)
{
while(a != NULL)
{
printf("%d \n",a->data);
a = a->next;
}
return;
}
void add_to_node(List_Node *a,int val)
{
a->data = val;
}
struct List* create_list()
{
struct List* list = (List*) malloc(sizeof(List));
list->head = NULL;
return list;
}
The code is dereferencing a NULL pointer as a->head is NULL:
list->head = NULL; /* inside create_list()` and 'list' returned to ...*/
List_Node *ind = a->head; /* ... inside main(), and then passed to */
add_to_node(ind,6); /* add_to_node() ... */
a->data = val; /* and dereferenced inside add_to_node(). */
Dereferencing a NULL pointer is undefined behaviour. To correct, malloc() memory for a List_Node and assign to a->head. Recommend creating an add_node() function that allocates memory and assigns the new int value to newly malloc()d node.
Do I cast the result of malloc?
As all have pointed out, you are dereferencing a NULL pointer as your list->head contains NULL.
Another thing I should point out is that, you are creating a List. but not any Node. There is no node in the list. You have to allocate memory for a Node and then use it.
So, instead of add_to_node(), you may use a function add_node that will take the list or the head and the value as parameters, create a node(i.e. allocating memory for the node), set the value and add it to the list.
Also, in your case, the structure List is redundant as it contains only one member. instead you can simply use List_node* head.
What you are doing:
In create_list:
Allocating memory for a List pointer.
Setting the list's head to NULL.
In add_to_node:
Setting the specified node pointer's data element to the specified val.
In main:
Creating a List pointer a by calling create_list. This list has a NULL head.
Initializing a List_Node pointer, ind, to point to the created list's head (which is NULL).
Trying to set ind's data element to 6 by calling add_to_node.
This is where your program is causing the access violation exception.
ind = NULL. Therefore NULL->data = undefined behaviour.
What you should be doing:
In create_list:
Allocate memory for a List pointer, say linked_list.
Allocate memory for linked_list's head pointer.
For the linked_list's head, initialize data and the next pointer to 0 and NULL respectively.
In add_to_node:
Do the same thing you're doing now.
In main:
Create a List pointer a by calling create_list. Now, this list will have a valid, initialized NULL head, but with no meaningful data.
Set the list's head data by calling add_to_node(a->head, 6);.
Note: This will only ensure you have a head node in your list. Nowhere are you creating additional nodes.