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).
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.
What I did :
I added a pointer in the parameter of malloc(struct Node *) which is usually malloc(struct Node).
Problem :
When I am allocating memory for the size of a pointer then how the code is working?
malloc() is allocating 8 bytes of memory and returning the pointer
So the pointer points to an 8 bytes memory block which but further I am storing more data in it.
struct Node
{
int data;
struct Node *next;
};
struct Node *GetNode(int data)
{
struct Node *node = (struct Node *)malloc(sizeof(struct Node *));
node->data = data;
node->next = NULL;
return node;
}
Difference in size:
I know that malloc is allocating different sizes because I did this
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node *next;
};
void main(){
int i = sizeof(struct Node);
int j = sizeof(struct Node *);
printf("%d,%d", i, j);
}
Output
16,8
What you've done is undefined behavior. It could work (on some systems, on certain days of the week), or it could crash, or it could produce incorrect results in seemingly unrelated calculations.
Imagine you rent a garage space for your truck, but to save money you request a space for a car. What happens when you drive your truck in? Maybe it fits, maybe you wreck the truck, maybe you destroy the garage.
So don't do that, and to help you find cases where you've made similar mistakes, build with Address Sanitizer. It will log when you access memory in an invalid way.
UB is a fickle mistress. Sometimes agreeable; sometimes not.
That is why you should use a syntax that makes it less likely to make mistakes:
struct Node *node = (struct Node *)malloc(sizeof(struct Node *)); // bad
struct Node *node = malloc( sizeof *node ); // good
No casting, and no redundancy.
I would even recommend using typedef's to free yourself from "struct, struct, struct".
typedef struct s_node
{
int data; // use more indentation, please. whitespace is cheap.
struct s_node *next;
} Node_t;
/* ... */
Node_t *node = malloc( sizeof *node ); // better
Finally, a lot of hours are wasted tracking down bugs that appear and disappear. Until performance becomes a real issue that you understand, I'd recommend using calloc() as the go-to allocation function:
Node_t *node = calloc( 1, sizeof *node ); // best
You can sleep easier knowing the byte values will be repeatable from run to run.
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).
I've created a Stack structure in C. When the stack is initialized with a value, I am able to print it back and receive the correct output. However, after pushing a new string, the print function prints what appears to be a random character (ASCII 177).
Originally, I implemented this project with pointers, but I was unable to get it working. Instead, I opted to only use a pointer for the Node *nodes member of Stack. That way, when I need to grow the stack, I can just multiply the amount of memory required by Stack.size. However, this approach has not worked yet either.
#define MAX_DATA 64
struct Node{
char val[MAX_DATA];
};
struct Stack{
int size;
struct Node *nodes;
};
These are used as follows:
struct Node node = {.val = "Test"};
struct Stack stack = newStack(node);
printStack(stack);
The newStack function initializes nodes properly. For the sake of inclusion:
struct Stack newStack(struct Node node)
{
struct Stack stack;
stack.size = 1;
stack.nodes = (struct Node*) malloc(sizeof(struct Node));
stack.nodes[0] = node;
return stack;
}
The stack is then printed iteratively in printStack(), with stack.size being the upper bound of the for-loop.
The trouble comes when I try to run:
struct Node node2 = {.val = "Test1"};
push(stack, node2);
printStack(stack);
The push function aims to create a temporary stack and assign the value of the stack to it. After this, the size is incremented, the pointer to the nodes is freed, and new memory is allocated, with room for a new member at the end.
void push(struct Stack stack, struct Node node)
{
struct Stack temp_stack = stack;
stack.size += 1;
free(stack.nodes);
stack.nodes = (struct Node*) malloc(sizeof(struct Node) * stack.size);
for(int i = 0; i < temp_stack.size; i++){
stack.nodes[i] = temp_stack.nodes[i];
}
stack.nodes[stack.size - 1] = node;
}
Needless to say, this doesn't execute properly.
The expected output would be:
Test
Test1
But, instead, I receive only ASCII-177. It is also worth noting that the execution hangs after it prints that and moves to the new line. This results in Aborted (core dumped).
Am I improperly freeing and re-allocating memory? Any help would be appreciated. Thank you in advance!
It's worth remembering that in C, passing a struct to a function is pass-by-value, i.e., the function gets a copy of the struct. All members of the struct, including pointer variables (but not whatever the pointer references), are duplicated.
So in the push function, think about what happens to the original when you modify this copy (e.g., stack.size += 1, and also when you free() the stack.nodes.
Thank you to peekay for the recommendations. I ended up doing a re-write. It became quite a bit simpler. I did remove a layer of "visibility" by storing the nodes as a pointer, but I suppose this implementation is a bit more true to the data structure.
Node is implemented as a means to hold data, and the user doesn't interact with it directly. It also points to the following Node. Stack is implemented to hold the top Node, and also the size of the Stack.
Node:
struct Node{
char val[MAX_DATA];
struct Node *next;
};
Stack:
struct Stack{
struct Node *top;
int size;
};
Push:
void push(struct Stack *stack, char *newVal)
{
struct Node *newNode;
newNode = (struct Node*) malloc(sizeof(struct Node));
strcpy(newNode->val, newVal);
newNode->next = stack->top;
stack->top = newNode;
stack->size++;
}
Usage:
struct Stack stack;
newStack(&stack);
push(&stack, "Test");
push(&stack, "Test1");
push(&stack, "Test2");
push(&stack, "Test3");
Complete Code
Updated, accessible Nodes
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".