C Linked List with dynamic node size - c

Im trying to create a linked list in C, where each node has a specific size entered by the user when the program launches. I already thought of a struct:
struct ListNode{
char * str;
struct ListNode * next_node;
};
but here the size of each node is fixed. Any ideas?
Thanks a lot in advance.

It seems you need your data size that the node holds to change each time. You can achieve this by using a constant size node that holds a pointer to dynamically allocated data.
Note that in the example below the struct size stays sizeof(void*)+ sizeof(node*)
but the size of data allocated for each node changes using the user input.
typedef struct Dnode
{
void* data;
struct Dnode* next;
}Dnode;
Dnode* CreateDnode(size_t data_size_bytes)
{
Dnode* newNode = NULL;
newNode = malloc(sizeof(Dnode));/*always the same*/
if(NULL == newNode)
{
return NULL;
}
newNode->data = malloc(data_size_bytes);/*changes by input*/
if(NULL == newNode->data)
{
return NULL;
}
newNode->next = NULL;
return newNode;
}

Sounds like you may be looking for the "flexible array member" feature whereby an incomplete array is placed at the end of a structure:
struct ListNode {
struct ListNode *next;
char data[];
};
This is allocated like:
struct ListNode *node = malloc(sizeof *node + data_size_bytes);
Then we can store values in node->data[i] for i from 0 to data_size_bytes - 1. The whole structure and data are in one linear block.
Note that a structure with a flexible member can't be used as an array element type.
Before the ISO C standard added the flexible array member in 1999, this was done as a popular "struct hack" using an array of size 1. If you're constrained to working in C90 it goes like this:
struct ListNode {
struct ListNode *next;
char data[1];
};
Now sizeof ListNode includes the one element array, and quite likely padding for alignment. For instance on a system with four byte pointers, the size is quite likely eight. If we use the same malloc line, we will allocate excess memory. The right malloc expression to use for the C90 struct hack:
#include <stddef.h>
struct ListNode *node = malloc(offsetof(struct ListNode, data) + data_size_bytes);
Unlike the flexible array member feature, the struct hack doesn't have formally well-defined behavior; it's just something that "works if it works".

Related

Why write * sign before declaring a struct variable, which has a self referencing pointer in C?

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.

Implementing a simple linked list in C without malloc

All the implementations I have seen online use pointer to declare nodes and then will use malloc to create space for them like this:
struct Node
{
int data;
struct Node *next;
};
int main()
{
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));
...
But I can also create the same without pointers and malloc like this:
struct node {
int id;
struct node* next;
};
struct node head = {0, NULL};
struct node one = {1, NULL};
struct node two = {2, NULL};
struct node tail = {3, NULL};
int main(){
head.next = &one;
one.next = &two;
two.next = &tail;
...
My question is, why the 1st method is mostly the one used, why do we need to declare each node as pointer and why do we need malloc?
(Just to point out I know why struct Node *next; is declared as pointer int the struct declaration).
You should do this with local variables, not global ones, but the general idea would be the same. You should also steer towards having arrays and not heaps of otherwise unrelated variables:
struct node {
int id;
struct node* next;
};
int main(){
struct node nodes[4];
for (int i = 0; i < 4; ++i) {
nodes[i].id = (3 - i);
if (i != 0) {
nodes[i].next = &nodes[i-1];
}
}
return 0;
}
Where something like that assembles them in reverse order for convenience, but they're all grouped together in terms of memory initially.
malloc is used because you often don't know how many you're going to have, or they get added and removed unpredictably. A general-purpose solution would allocate them as necessary. A specialized implementation might allocate them as a single block, but that's highly situational.
Here the lifespan of nodes is within that function alone, so as soon as that function ends the data goes away. In other words:
struct node* allocateNodes() {
struct node nodes[10];
return &nodes; // Returns a pointer to an out-of-scope variable, undefined behaviour
}
That won't work. You need a longer lived allocation which is precisely what malloc provides:
struct node* allocateNodes() {
struct node *nodes = calloc(10, sizeof(struct node));
return nodes; // Returns a pointer to an allocated structure, which is fine
}
The problem is if you malloc you are responsible for calling free to release the memory, so it becomes more work.
You'll see both styles used in code depending on the required lifespan of the variables in question.
If you know ahead of time exactly how many items will be in your list, then you're probably better off using an array rather than a list. The whole point of a linked list is to be able to grow to an unknown size at runtime, and that requires dynamic memory allocation (i.e., malloc).

How to initialize all the pointer fields of struct pointer to NULL?

I have the following struct:
struct node {
int data;
struct node *next;
};
struct node *n1 = malloc(sizeof(struct node));
I am not sure how initialize all the pointer fields of struct pointer to NULL without causing any potential for memory leaks?
You need to initialize the members of the structure after you allocate it with malloc:
struct node {
int data;
struct node *next;
};
struct node *n1 = malloc(sizeof(struct node));
n1->data = 0;
n1->next = NULL;
If you want to initialize your structure in one step with default values, which can be handy if it is much larger, use a static structure with these defaut values:
struct node def_node = { 0, NULL };
struct node *n1 = malloc(sizeof(struct node));
*n1 = def_node;
Alternately, you can use the C99 syntax:
struct node *n1 = malloc(sizeof(struct node));
*n1 = (struct node){ 0, NULL };
As commented by Leushenko, you can shorten the initializer to { 0 } for any structure to initialize all members to the appropriate zero for their type:
struct node *n1 = malloc(sizeof(struct node));
*n1 = (struct node){ 0 };
You have four choices:
1) Set the pointers manually, e.g. node-> next = NULL;
2) Use calloc() to zero out the memory when you allocate it
3) Use memset() to zero out the memory after you've allocated it.
... OR ...
4) Don't worry about explicit initialization until you actually need to use the struct. Design your program such that you make sure any pointer is assigned before you try to read it.
FYI, this is one of the main purposes of a "constructor" in OO languages like C++ or C#: to initialize "class invariants".
PS:
5) I forgot about C99 struct initialization, which Leushenko mentioned:
what is the difference between struct {0} and memset 0
struct A
{
int x;
int y;
};
...
A a = {0};
This is vastly preferred to either calloc() or memset().
It also applies to other initialization values besides "0":
C99 Standard 6.7.8.21
If there are fewer initializers in a brace-enclosed list than there
are elements or members of an aggregate, or fewer characters in a
string literal used to initialize an array of known size than there
are elements in the array, the remainder of the aggregate shall be
initialized implicitly the same as objects that have static storage
duration.

Allocating space to a node pointer

I am currently attempting to use a doubly linked list to sort some data. I am having trouble creating a new node with the given data. Below was the code given to me:
#ifndef LIST_H_
#define List_H_
#define MAX_SYMBOL_LENGTH 7
struct order {
int id;
char symbol[MAX_SYMBOL_LENGTH];
char side;
int quantity;
double price;
};
typedef struct order* OrderPtr;
typedef struct onode* NodePtr;
struct onode {
OrderPtr data;
NodePtr next;
NodePtr prev;
};
This is the code that I have written using list.h as a header.
Here is the code that seemingly keeps crashing:
#include "list.h"
NodePtr newNode(OrderPtr data){
NodePtr node = (NodePtr)malloc(sizeof(NodePtr));
//node->data = (NodePtr)malloc(sizeof(OrderPtr));
//*node->data = *data;
node->data = data;//This is the one I am having problems with
node->next = NULL;
node->prev = NULL;
return node;
}
It compiles fine but when I try and submit it to an online grader it says that it does not work.
Here is my thought process,
create memory for NodePtr.
create memory for NodePtr->data.
and then assign the values of data passed from the function to the values in Node->Ptr.
But I do not know how to allocate memory for NodePtr->data.
NodePtr node = (NodePtr)malloc(sizeof(NodePtr));
Isn't doing what you are thinking. It's allocate space to hold a pointer same as sizeof(int*), it's 4 bytes on 32-bit machine, usually.
You need to do NodePtr node = malloc(sizeof(struct onode)); instead of.
data member should be result to a malloc(sizeof(struct order));
Also, don't cast result value from a malloc() call.
NodePtr is a pointer to a node and not the node itself. You're only allocating enough memory for a pointer and not all the members of the onode structure. You'll want to call malloc with sizeof(struct onode).

How to use a struct in C?

This is code for a linked list in the C programming language.
#include <stdio.h> /* For printf */
#include <stdlib.h> /* For malloc */
typedef struct node {
int data;
struct node *next; /* Pointer to next element in list */
} LLIST;
LLIST *list_add(LLIST **p, int i);
void list_remove(LLIST **p);
LLIST **list_search(LLIST **n, int i);
void list_print(LLIST *n);
The code is not completed, but I think it's enough for my question. Here at the end of struct node "LLIST" is used, and it's also used as a return type in the prototyping of the function list_add. What is going on?
That's a typedef. It's actually doing two things at once. First, it defines a structure:
struct node {
int data;
struct node *next;
}
And then does a typedef:
typedef struct node LLIST;
That means LLIST is a type, just like int or FILE or char, that is a shorthand for struct node, your linked-list node structure. It's not necessary - you could replace LLIST with struct node in all of those spots - but it makes it a bit easier to read, and helps hide the implementation from pesky end-users.
LLIST is just another type name for the struct that has been created. In general, the following format will create a type "NAME" that is a "struct x":
typedef struct x { ... } NAME;
C requires that you reference structs with a "struct" prefix, so it's common to introduce a typedef for less verbose mention.
That is, the declaration of your struct has two parts, and can be rewritten as such:
struct node {
int data;
struct node *next; /* pointer to next element in list */
};
typedef struct node LLIST;
So, LLIST is just another name for struct node (thanks Chris Lutz).
typedef creates a new "type" in your program, so the return value and types of parameters of those functions are just your struct. It is just shorthand for using struct node for the type.
If you were to create a new node, you could do it like this (using the type):
LLIST *node = malloc(sizeof(LLIST));
node->data = 4;
node->next = someOtherItem;
list_add(node, 1)
Also, with the function prototypes in your question, you don't really need the double pointers; since the data in your struct is just an int, you could do something like
LLIST *list_add(int data, int position);
then the list_add function would handle the allocation, copy the int into the struct and add it to the linked list.
Putting it in at a certain position is as simple as changing the next pointer in the node before it to the address of the newly allocated node, and the next pointer in the new node to point at the next one (the one the node before that one was originally pointing at).
Keep in mind that (given the rest of your function prototypes) you will have to keep track of pointers to every node you create in order to delete them all.
I'm not sure I understand how the search function will work. This whole thing could be implemented a lot better. You shouldn't have to provide the location of a node when you create it (what if you specify a higher number than there are nodes?), etc.
LLIST* is a pointer to a structure defined by the LLIST struct.
You should do
LLIST* myList = malloc(sizeof(LLIST)*number_of_elements);
to have some memory allocated for this list. Adding and removing items requires you to reallocate the memory using realloc. I've already written some piece of code for lists (made with arrays).
I might post the code as soon as I'm home, which is currently not the case.

Resources