I'm trying to implement a node structure in C that can have arbitrary many child nodes. I wanted to do this idea by using a pointer to a pointer to a struct instead of using an array:
struct Node {
char name[10]; // Name of the node.
int data; // The data it holds.
struct Node *parent; // The parent node.
struct Node **child; //
};
(I don't know if this is the best or even a good but I'm just playing around to learn C better).
I also implemented a print function that prints the members:
void print(struct Node node);
(I know this only prints one node so it wouldn't work for a node with multiple child-nodes).
However, when I try to use this in a main function I get a segmentation fault (core dump):
#include <stdio.h>
#include <stdlib.h>
struct Node {
char name[10]; // Name of the node.
int data; // The data it holds.
struct Node *parent; // The parent node.
struct Node **child; //
};
void print(struct Node node) {
printf("Name: %s\n", node.name);
printf("Data: %d\n", node.data);
printf("Parent: %s\n", (*node.parent).name);
printf("Children: %s\n", (**node.child).name);
}
int main() {
struct Node n1 = { "Parent", 1, NULL, NULL };
struct Node n2 = { "Child1", 2, &n1, NULL };
*n1.child = &n2;
print(n1);
print(n2);
return 0;
}
Can anybody see what I'm doing wrong here and what I should do instead?
Kind regards,
Edit:
Actually what I wanted to achieve was to create the child member like this (I'm using an example with an array of integers to illustrate what I mean):
int *p = malloc(sizeof(int));
*p =1;
*(p+1)=2;
but instead of p pointing to integers having it point to pointers to struct Node. Is this doable?
You get a segmentation fault because you do not test if the parent node is valid, nor if the child node is a valid pointer, nor that the pointer it points to is valid too. The initialization of n1.child[0] is incorrect too.
*n1.child = &n2; has undefined behavior because n1.child is a null pointer.
printf("Parent: %s\n", (*node.parent).name); has undefined behavior for n1;
printf("Children: %s\n", (**node.child).name); has undefined behavior for n2.
Alos note that it is idiomatic in C to pass structure pointers rather than copies of structures to functions such as print.
Here is a modified version, assuming child, if not NULL points to a NULL terminated array of node pointers.
EDIT: I added an add_child function to illustrate how to construct trees from individual nodes.
#include <stdio.h>
#include <stdlib.h>
struct Node {
char name[10]; // Name of the node.
int data; // The data it holds.
struct Node *parent; // The parent node.
struct Node **child; // if not NULL, points to a NULL terminated array of pointers.
};
void print(const struct Node *node) {
if (node) {
printf("Name: %s\n", node->name);
printf("Data: %d\n", node->data);
if (node->parent) {
printf("Parent: %s\n", node->parent->name);
}
if (node->child) {
printf("Children:");
for (int i = 0; node->child[i]; i++) {
printf("%s %s", i > 0 ? "," : "", node->child[i]->name);
}
printf("\n");
}
}
}
// add a child node to a parent's child list.
// return 0 upon success or an error code on failure
int add_child(struct Node *parent, struct Node *chid) {
if (parent == NULL)
return 1;
if (child == NULL)
return 2;
size_t nchild = 0;
if (parent->child != NULL) {
while (parent->child[nchild] != NULL)
nchild++;
}
struct Node *new_child = realloc(parent->child, (nchild + 2) * sizeof(*new_child));
if (new_child == NULL)
return 3;
parent->child = new_child;
parent->child[nchild++] = child;
parent->child[nchild] = NULL;
child->parent = parent;
return 0;
}
int main() {
struct Node n1 = { "Parent", 1, NULL, NULL };
struct Node n2 = { "Child1", 2, NULL, NULL };
struct Node n3 = { "Child2", 3, NULL, NULL };
add_child(&n1, &n2);
add_child(&n1, &n3);
print(&n1);
print(&n2);
print(&n3);
return 0;
}
You've commented out the print function, but you're trying to call it to print the nodes.
n1.child is NULL pointer, you dereference it here *n1.child = &n2;
this why you get segfault, just make child normal pointer not double pointer it will solve the problem
struct Node {
char name[10]; // Name of the node.
int data; // The data it holds.
struct Node *parent; // The parent node.
struct Node *child; //};
void print(struct Node node) {
printf("Name: %s\n", node.name);
printf("Data: %d\n", node.data);
printf("Parent: %s\n", (*node.parent).name);
printf("Children: %s\n", (*node.child).name);}
int main() {
struct Node n1 = { "Parent", 1, NULL, NULL };
struct Node n2 = { "Child1", 2, &n1, NULL };
n1.child = &n2;
print(n1);
print(n2);
return 0;}
Related
I have a list defined as
typedef struct node {
Voo *voo;
ListaReservas nodeReservas; /* Ignore this */
struct node *next;
} *Node;
I created some functions to help me add or remove nodes from the list like:
/* creates a node */
Node criaNode(Voo v) {
Node new = (Node)malloc(sizeof(struct node));
new->voo = &v;
/* I had new->voo = v; but vscode told me it was wrong so i changed it to &v */
new->next = NULL;
return new;
}
Voo is defined as:
typedef struct {
int dia;
int mes;
int ano;
} Data;
typedef struct {
int horas;
int minutos;
} Tempo;
typedef struct {
char codigo[LEN_CODIGO + 1];
char partidaID[LEN_ID + 1];
char chegadaID[LEN_ID + 1];
Data datapartida;
Tempo horapartida;
Tempo duracao;
Data datachegada;
Tempo horachegada;
int capacidade;
} Voo;
Now I wanted to iterate through the list and print its values as such
Voo *v;
for (n = headVoos; n != NULL; n = n->next) {
v = n->voo;
printf("%s %s %s %.2d-%.2d-%d %.2d:%.2d\n",
v->codigo, v->partidaID, v->chegadaID,
v->datapartida.dia, v->datapartida.mes, v->datapartida.ano,
v->horapartida.horas, v->horapartida.minutos);
}
The program is not printing correctly. For example where it should appear
AA1 AAA AAD 16-03-2022 14:50
its appearing instead
� 146187376-32765--1940381952 40355300:50
What's causing this and how can I avoid it in the future?
EDIT
After replacing in the struct node the Voo *voo definition by Voo voo, I am now getting an error in one of the auxiliary functions:
/* deletes node */
Node eliminaNode(Node head, Voo v)
{
Node n, prev;
for (n = head, prev = NULL; n != NULL; prev = n, n = n->next)
{
if (n->voo == v) /* expression must have arithmetic or pointer error */
{
if (n == head)
head = n->next;
else
prev->next = n->next;
free(n->next);
free(n);
break;
}
}
return head;
}
In criaNode you're taking the address of the parameter v and returning it from the function via a pointer to dynamic memory. That address is no longer valid after the function returns. Subsequently dereferencing that invalid address then triggers undefined behavior.
It probably makes more sense for struct node to contain a Voo directly instead of a pointer to one. So change the member to a non-pointer:
Voo voo;
And assign the parameter directly:
new->voo = v;
There are multiple problems here:
there seems to be a confusion between structures and pointers to structures. In C, you must understand the difference between manipulating objects (allocating as local objects or from the head, passing as arguments or returning as values) and pointers to objects, which are a more idiomatic as arguments to functions and allow functions to modify the object they point to.
the confusion is amplified by a very error prone construction: hiding pointers behind typedefs. Do not do that, define object types for the actual structure, using the same or a different name as the struct tag, and make all pointers explicit with the * syntax.
you pass an actual Voo object as an argument and allocate a list node using the address of this argument. This is incorrect because the argument will be discarded as soon as the function returns, makeing the list point to invalid memory and explaining the weird output you observe.
Node eliminaNode(Node head, Voo v) should take a pointer to the head node and return a success indicator. It should take a Voo * argument and it should not free(n->next) because the next node is still in use after the removal.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#define LEN_CODIGO 30
#define LEN_ID 30
typedef struct Data {
int dia;
int mes;
int ano;
} Data;
typedef struct Tempo {
int horas;
int minutos;
} Tempo;
typedef struct Voo {
char codigo[LEN_CODIGO+ 1];
char partidaID[LEN_ID + 1];
char chegadaID[LEN_ID + 1];
Data datapartida;
Tempo horapartida;
Tempo duracao;
Data datachegada;
Tempo horachegada;
int capacidade;
} Voo;
typedef struct Node {
struct Voo *voo;
//ListaReservas nodeReservas; /* Ignore this */
struct Node *next;
} Node;
/* creates a node */
Node *criaNode(Voo *v) {
/* allocation with calloc is safer as the object will be initialized to 0 */
Node *nodep = calloc(1, sizeof(*new));
if (nodep) {
nodep->voo = v;
nodep->next = NULL;
}
return nodep;
}
/* deletes node */
int eliminaNode(Node **head, Voo *v) {
for (Node *n = *head, *prev = NULL; n != NULL; prev = n, n = n->next) {
if (n->voo == v) {
if (n == *head)
*head = n->next;
else
prev->next = n->next;
free(n);
return 1; /* article was found and freed */
}
}
return 0; /* article was not found */
}
void printList(const Node *head) {
for (const Node *n = head; n != NULL; n = n->next) {
const Voo *v = n->voo;
printf("%s %s %s %.2d-%.2d-%.2d %.2d:%.2d\n",
v->codigo, v->partidaID, v->chegadaID,
v->datapartida.dia, v->datapartida.mes, v->datapartida.ano,
v->horapartida.horas, v->horapartida.minutos);
}
}
So I'm a Python programmer and I'm trying to teach myself C. Just as practice, I've been trying to implement a simple Binary Search Tree in C. I've never had to work with memory allocation or pointers before and its been causing a lot of errors.
My program has been giving me exit code -1073740940 (0xC0000374) which I understand means that the heap has been corrupted. It's a bit of a long program, so I just included the offending function.
This insert function is repeatedly called using a for loop to insert the contents of an array into the binary search tree. The array's contents are 5, 4, 6, 3, 7, 2, 8, 1, 9, and 0 (designed to make the tree balanced).
So the function first has 5 passed to it. The pointer called by pBST->listRoot is NULL (pBST is a pointer to a list struct), so insert 5 as a the root node. This works fine. Then 4 is passed to the function. Since there is already a root, it checks the children of that root. 4 is less than 5 so check 5's left child. The pointer for 5's left child is null, so it attempts to insert 4 as a new node. This is the line that crashes the program:
struct Node* pTemp = calloc(1, sizeof(struct Node));
I've tried a couple variations of this line. Here's the kicker: cLion's debugger cannot reproduce this. When I run it through the debugger, it works perfectly. I think it has to do with the fact that the debugger uses the same memory addresses every time for reproducibility. I left the debugging printf statements and added the code for the Node and binarySearchTree structs.
typedef struct Node BSTNode;
struct Node {
BSTNode* parent;
BSTNode* left;
BSTNode* right;
int* data;
};
typedef struct {
BSTNode* listRoot;
int nodeCount;
} binarySearchTree;
void insert(int Value, binarySearchTree* pBST) {
/*
* This function
*/
//====DEBUG CODE============
int debugIterations = 0;
printf("Now inserting %d \n", Value);
//=====END DEBUG CODE=======
//if no root, make it the root
if (pBST->listRoot == NULL) {
struct Node* newNode = calloc(1, sizeof(binarySearchTree));
(*pBST).listRoot = newNode;
(*pBST).listRoot->data;
(*pBST).listRoot->data = Value;
//pBST->listRoot->data = Value;
pBST->listRoot->parent = NULL;
pBST->listRoot->right = NULL;
pBST->listRoot->left = NULL;
return;
} else {
struct Node* pCursor = pBST->listRoot;
while (1){
printf("Iterations: %d \n", debugIterations);
debugIterations++;
//Check if the number is the same
if (pCursor->data == Value){
printf("ERROR: Tried to insert duplicate value into tree");
return;
}
//Is the value > the node?
else if (pCursor->data < Value) {
//DEBUG
printf("== check succeeded, now value > data\n");
// Is the value a Null?
if (pCursor->right == NULL) {
//DEBUG
printf("Running function to insert %d as a new node to the right\n", Value);
//If yes, then insert the value as a nul
//Create Node
struct Node* pTemp = calloc(1, sizeof(binarySearchTree));
pTemp->data = Value;
pTemp->parent = pCursor;
pCursor->right = pTemp;
pTemp->left = NULL;
pTemp->right = NULL;
return;
}
//If no, then iteravely continue.
else {
printf("Iteravely continuing to the right");
pCursor = pCursor->right;
continue;
}
}
//Is the value < the root?
else {
//DEBUG
printf("== check succeeded, now value < data\n");
//Is the value a Null?
if (pCursor->left == NULL) {
//DEBUG
printf("Running function to insert %d as a new node to the left\n", Value);
//If yes, then insert the value where the null is.
//Create Node
struct Node* pTemp = (struct Node*)calloc(1, sizeof(struct Node));
printf("Successfully declared and allocated memory");
pTemp->data = Value;
pTemp->parent = pCursor;
pCursor->left = pTemp;
pTemp->left = NULL;
pTemp->right = NULL;
return;
}
//If no, then iteravely continue
else{
printf("Iteravely continuing to the right");
pCursor = pCursor->left;
continue;
}
}
}
}
}
The line
struct Node* pTemp = calloc(1, sizeof(binarySearchTree));
is wrong. The structure binarySearchTree has one pointer and one int, but the structure struct Node has 4 pointers, so struct Node should be larger than binarySearchTree and this allocation will allocate less space than required, leading to out-of-range access.
It should be:
struct Node* pTemp = calloc(1, sizeof(*pTemp));
or
struct Node* pTemp = calloc(1, sizeof(struct Node));
Also it looks very weird to store the data int Value in the member int* data; with (*pBST).listRoot->data = Value;. It looks like the member should be int, not int*.
I've been learning C and am having problems using linked lists. When looping over a pointer to a linked list I run into segmentation faults and I'm not sure why.
Looking at similar questions the suggestion is to allocate the memory, but I find this answer confusing. Do you have to use heap memory for linked lists, and if so why?
Here is my code:
#include <stdio.h>
typedef struct Node {
char *name;
struct Node *next;
} Node;
typedef struct Thing {
Node *node;
} Thing;
Thing make_thing()
{
Thing t = {
.node = NULL
};
return t;
}
Thing * add_node(Thing *t, char *name)
{
Node node = {
.name = name,
.next = t->node
};
t->node = &node;
return t;
}
void print_nodes(Thing *t)
{
Node *n = t->node;
while(n != NULL) {
printf("Node: %s\n", n->name);
n = n->next;
}
}
int main()
{
printf("Start\n");
Thing t = make_thing();
add_node(&t, "one");
printf("First %s\n", t.node->name);
print_nodes(&t);
return 0;
}
You are using objects with automatic storage out of their scope:
Node node = {
.name = name,
.next = t->node
};
t->node = &node;
return t;
Here you leak the pointer &node, which is invalid (out of scope) after the return, to the caller and use it here:
printf("First %s\n", t.node->name);
You have to allocate memory by using malloc() for your Node structure.
Example:
Node *node = malloc(sizeof *node);
node->name = name;
node->next = t->node;
t->node = node;
return t;
You have to care about freeing the memory when it is no longer used to prevent memory leaks.
I'm working on a binary tree with a list tacked on to the data, yet I can't tell if the list is being populated or not. The code runs alright but when I try to call to print out the tree I get a freeze in my code. I believe everything is being pointed to properly but it's obvious there is a flaw in the logic somewhere.
struct declarations
typedef struct lineList
{
int lineNum;
LIST *next;
}LIST;
typedef struct nodeTag{
char data[80];
LIST *lines;
struct nodeTag *left;
struct nodeTag *right;
} NODE;
declaration and pass to function from main
NODE *root = NULL;
readFromFile(argv[1], root);
readfromfile(working function) then calls insertword
insertWord(root, keyword, lineNum);
insertWord, addToList functions(problem area)
NODE *allocateNode(char *data, int line)
{
NODE *root;
LIST *newNum;
if(!(root = (NODE *) malloc (sizeof(NODE))))
printf( "Fatal malloc error!\n" ), exit(1);
strcpy(root->data, data); //copy word
(root)->left = (root)->right = root->lines = NULL; //initialize
if (!(newNum =(LIST *) malloc (sizeof(LIST))))
printf( "Fatal malloc error!\n" ), exit(1);
newNum->lineNum = line;
root->lines = newNum;
return root;
}
/****************************************************************
ITERATIVE Insert
*/
NODE *insertWord(NODE *root, char *data, int line)
{
NODE *ptr_root = root;
printf("inserting %s\n", data);
if(root == NULL)
{
root = allocateNode(data, line);
return root;
}
while(ptr_root)
{
if (strcmp(data, ptr_root->data > 0))
{
if(ptr_root->right)
ptr_root = ptr_root->right; //traverse right
else
ptr_root->right = allocateNode(data, line);
}
else if (strcmp(data, ptr_root->data) < 0)
{
if(ptr_root->left) //traverse left
ptr_root = ptr_root->left;
else
ptr_root->left = allocateNode(data, line);
}
else
{
printf("Node already in the tree!\n");
addToList(ptr_root, line);
}
}
printf("5\n");
return root;
}
void printTreeInorder(NODE *root)//simple print, freeze on call to function
{
if(root)
{
printTreeInorder(root->left);
printf( "%s\n", root->data );
printTreeInorder(root->right);
}
return;
}
Let's look at insertWord():
At the end of your while loop, we know that ptr_root == NULL.
We then allocate memory for ptr_root.
We then initialize the contents of ptr_root.
We then perform a memory leak on ptr_root.
Note that you need to retain the parent of the new node, and you need to point the its left or right pointer to this new node.
It also sounds like you understand how to use a debugger. If that's true, you should be able to see that root doesn't change between calls to insertWord().
In the code that you've posted with an attempted fix, you're missing one key thing. Let's look at a function:
void foo(NODE *root) {
printf("before malloc: %p\n", root);
root = malloc(sizeof(NODE));
printf("after malloc: %p\n", root);
}
int main() {
NODE *root = NULL;
printf("before function: %p\n", root);
foo(root);
printf("after function: %p\n", root);
}
This code will produce:
before function: 0x0
before malloc: 0x0
after malloc: 0x123ab129
after function: 0x0
Note that any changes to the value of root is not propagated out of the function. Things that you change to *root would though.
I am still very new to C, and am trying to figure out why I (believe) that I am getting a segmentation fault. I say believe, because the exe stops working, and so I just try and run it in Eclipse's debugger, and that's where I see the error happening. Any help/suggestions/criticisms are highly welcomed.
#include<stdio.h>
#include<stdlib.h>
typedef struct node{
struct node *left;
struct node *right;
double key;
} node;
void addNode(double value, node **node);
double dRand();
//node* search(double value, node *root);
void killTree(node *root);
int main(void)
{
int nodesToAdd, i;
node *n = NULL;
node **p = &n;
nodesToAdd = 10;
for(i=0;i<nodesToAdd;i++)
{
printf("DEBUG: Adding node %d to tree\n", i+1);
addNode(dRand(), p);
}
printf("DEBUG: Finished creating tree\n");
printf("DEBUG: Freeing memory of tree\n");
killTree(n);
return 0;
}
double dRand()
{
return ((double)rand()/RAND_MAX)*10;
}
void addNode(double value, node **tree)
{
node *insert = malloc(sizeof(*insert));
insert->key = value;
while(*tree){
if(value < (*tree)->key) tree = &(*tree)->left;
else if(value > (*tree)->key) tree = &(*tree)->right;
else return;
}
*tree = insert;
}
void killTree(node *node)
{
if(!node){}
else
{
killTree(node->left);
killTree(node->right);
printf("DEBUG: Deleting pointer to node of value %f from mem\n", node->key);
free(node);
}
}
EDIT: I think that the error comes from trying to reference the right and left nodes before they are allocated memory, but I'm not sure what it is that I am doing wrong.
EDIT2:Thanks so much, that worked wonderfully!
You have a memory leak in your addNode function if a match is found. You allocate, then search. You should search, then allocate only if the search failed.
Regarding your crash, you're not initializing a new node's left and right pointers to NULL. This is critical. The next time you enter the tree to chase down a search, you will dereference indeterminate pointers, and invoke undefined behavior as a result.
Perhaps something like this:
void addNode(double value, node **tree)
{
// search first
while (*tree)
{
if (value < (*tree)->key)
tree = &(*tree)->left;
else if((*tree)->key < value)
tree = &(*tree)->right;
else return;
}
// no match, so add
*tree = malloc(sizeof(**tree));
(*tree)->key = value;
(*tree)->left = (*tree)->right = NULL; // note: set to null
}
Next, though not critical, your main() function has no need for p. You can use your node pointer by-address directly:
int main(void)
{
int nodesToAdd, i;
node *n = NULL;
nodesToAdd = 10;
for(i=0;i<nodesToAdd;i++)
{
printf("DEBUG: Adding node %d to tree\n", i+1);
addNode(dRand(), &n);
}
printf("DEBUG: Finished creating tree\n");
printf("DEBUG: Freeing memory of tree\n");
killTree(n);
return 0;
}
And for what it's worth, if your new to C, this isn't terrible. Grasping double-indirection is a common stall-point in the C learning curve, and your use in your add function wasn't terrible at all. Keep at it.