Storing a string in struct via an argument to a function - c

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.

Related

Is there anyway to give this value to my node

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.

Linked list node memory allocation

In creating a linked list we make a node structure and it consists of both data and a pointer to the next node. Later when we make a function to append elements onto the linked list, we make a temporary node to store the inputted data.
Let’s consider the following program-
#include<stdio.h>
struct node
{
int data;
struct node* link;
}
struct node* root=NULL;
void main(append)
{
struct node* temp;
temp= (struct node*)malloc(sizeof(struct node))
.....
}
My first question set:
In line 11, why do we need to mention (struct node*) before the malloc function?
What is the significance of that?
My second question set:
If we are making a doubly linked list which would have a node structure consisting of 2 pointers (for next and previous node), would we also initialize a pointer (for traversing the list) of the struct node type?
Is there a different way to initialize the pointer in that case?
The significance is to make bugs in your program,
The malloc will return void* and when you assign to your struct somthing* it will convert automaticlly.
You simply don't cast the result of malloc as it returns void* . There is one fine explanation here
A better solution might be :
struct node *temp;
temp = malloc(sizeof *temp);
why do we need to mention '(struct node*)' before the malloc function,
what is the significance of that?
By writing (struct node*) before the malloc function, you are type-casting the return value to the specified type. The cast here is optional and often frowned upon.
if we are making a doubly linked list which would have a node
structure consisting of 2 pointers(...
When making a doubly linked list, you should declare something like:
struct node {
int data;
struct node *next;
struct node *previous;
};
You can allocate space for a node by using the malloc function. The next and previous pointers are again pointers to struct nodes. Call malloc again to allocate space for the next element. For the first node, the previous should be NULL and for the last node, next should be NULL. Here is one implementation.
This is the because the return type of malloc is void*. (struct node*) is a cast using which you tell the compiler that you want to treat the value returned by malloc as a pointer to struct node.
For double linked list you can use,
struct node
{
int data;
struct node *next,*prev;
};
int main()
{
struct node *new_node=(struct node *)malloc(sizeof(node));
}
malloc returns the void pointer(can be checked and verified at the header ), and so the type casting is necessary while assigning it to the other type of variable.
Request you to read at the link https://www.tutorialspoint.com/cprogramming/c_type_casting.htm

Linked List access violation in C

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.

Preserving Structs without Dynamic Allocation

I've been battling with this problem for a few hours.
I have a doubly linked list implementation that does not require dynamic memory allocation.
Here's the insertion method. It inserts elem right before before. The struct list has two members, struct list_elem *next and struct list_elem *prev. list_elem is a struct that holds some data. Please note that this list implementation is correct. The problem is with the way I am using it. Please read on.
void list_insert(struct list_elem *before, struct list_elem *elem) {
/* "before" has to be an interior node or tail node to be able to insert "before" it */
assert (is_interior(before) || is_tail(before));
assert (elem != NULL);
elem->prev = before->prev;
elem->next = before;
before->prev->next = elem;
before-> = elem;
}
The way this list is initialized is as follows:
void list_init(struct list *list) {
assert(list != NULL);
list->head.prev = NULL;
list->head.next = &list->tail;
list->tail.prev = &list->head;
list->tail.next = NULL;
}
My main class does the following:
struct list some_list;
static struct list_elem head;
some_list.head = head;
static struct list_elem tail;
some_list.tail = tail.
list_init(&some_list);
This basically creates two static list_elem structs, head and tail. And passes it into the initialization function which will wire them up together.
Now to create an element, I do the following - here's what I am doing wrong
struct list_elem element_struct;
/* Initialize element_struct members here */
struct list_elem *data = &element_struct;
list_insert( list_begin(some_list), data);
Now this works to insert one item. Since some_list.head will point to data which will point to some_list.tail. My problem is that I do this in a loop. So, as any list does, it will enter multiple data in there. I either get a segfault or some other error saying my element is not an interior or tail node (due to assert) since in each loop iteration, the data struct, element_struct will be reinitialized. (list_elem holds pointers to each other).
So my question is, how would I preserve the nodes that have been inserted? The list is not supposed to use any dynamic allocation itself. In that case, would I dynamically allocate my list_elem structs, and pass a dynamically allocated element into the list?
If so, how can I dynamically allocate a struct?
If you need to dynamically-allocate a struct instance, it's as simple as MyStruct *p = malloc(sizeof(*p));, and then an associated free(p); at some point.

How do we free memory of node carrying pointer to some location

I have link list whose node structure is given below
struct node
{
char *p;
struct node *next;
}*start;
Now we char *p is pointer to memory location which allocated by malloc call.Similarly the whole is also allocated using malloc. Now would like to free the space occupied by both the malloc call ,something like this below
main()
{
struct node *tmp;
tmp=malloc(sizeof(struct node));
tmp->next=NULL;
tmp->p=malloc(2*sizeof(int));
free(tmp->p);
free(tmp);
}
Is it the right way to free memory or something is required here?
This is the right way but don't forget to assign pointers to NULL after using free otherwise the pointers will become dangling pointers.
Use them like this -
free(tmp->p);
tmp->p = NULL;
you are freeing correctly, although normally you would have a pointer to the first node then loop through the list by following the pointers. e.g.
struct node *first;
... list created, first pointing to first in list, where last next is == NULL ...
while (first != NULL)
{
struct node* next = first->next;
free( first->p );
free( first );
first = next;
}
btw why do you declare p as char* but allocate ints? typo?

Resources