This code creates a BST, fills it, and makes an effort to release resources. Two versions of release() are shown below:
typedef struct Node {
int d;
struct Node *left;
struct Node *right;
} Node;
int main() {
Node **tree = NULL;
tree = mkTree();
if (!tree) {
puts("problem\n");
return 1;
}
insert(7, tree);
insert(3, tree);
insert(9, tree);
insert(6, tree);
printTree(*tree);
release(tree);
free(tree);
return 0;
}
/* Make a new binary tree */
Node **mkTree() {
Node **t = malloc(sizeof **t);
return t;
}
/* insert datum d into tree */
bool insert(int d, Node **tree) {
Node *newptr = NULL;
if (tree == NULL) { /*ptr to rootptr NULL */
return false;
}
if (*tree == NULL) {
newptr = buildNode(d);
if (!newptr) {
return false;
}
*tree = newptr;
return true;
}
return insert(d, d < (*tree)->d ? &(*tree)->left : &(*tree)->right);
}
What I don't understand is why valgrind claims all resources are freed in BOTH cases (I and II) below. I try to clear each node using release(), and, at the end of main, I call free(tree) to clear Node **tree, which is declared in main.
I.
/* release resources by passing Node **tree */
void release(Node **tree) {
if (*tree) {
Node *here = *tree;
release(&here->left);
release(&here->right);
}
free(*tree);
}
II.
/* passing Node *tree. this shouldn't free anything, right? */
void release(Node *tree) {
if (tree) {
Node *here = tree;
release(here->left);
release(here->right);
}
free(tree);
}
Despite the choice, running this program with four insertions gives
==5182== HEAP SUMMARY:
==5182== in use at exit: 0 bytes in 0 blocks
==5182== total heap usage: 5 allocs, 5 frees, 60 bytes allocated
What's happening here? Is valgrind just keeping a tally count of the number of malloc's and free's?
Both versions of Release are doing the same thing. One just has an extra (and unnecessary) level of indirection. You can pass a pointer to a function and free that pointer; it is not necessary to pass the address of the variable holding the pointer.
In fact, the call to free does exactly that. It just accepts the pointer value (not the address of the variable holding the pointer).
Related
I'm trying to free a tree that is not binary. It includes dozens of leaves and paths.
Basicly it's a tree that starts with a root of a chess board position, and includes a lot of other positions.
The structs are the following:
typedef char chessPos[2];
typedef struct _treeNodeListCell treeNodeListCell;
typedef struct _treeNode
{
chessPos position;
treeNodeListCell* next_possible_positions;
} treeNode;
typedef struct _treeNodeListCell
{
treeNode* node;
struct _treeNodeListCell* next;
} treeNodeListCell;
typedef struct _pathTree
{
treeNode* root;
} pathTree;
Basicly I want to free a whole path tree. For example, the path tree looks the following:
So the root of path tree is the root with "C3" written in it.
(Ignore the parts with the blue "X" on them, it just means that these tree nodes aren't in the tree in my program)
This is the way I was trying to free the tree:
void freePathTree(pathTree* ptr)
{
freeTreeNode(ptr->root);
free(ptr);
}
void freeTreeNodeListCell(treeNodeListCell* tmp)
{
if (tmp->next != NULL)
{
freeTreeNodeListCell(tmp->next);
}
freeTreeNode(tmp->node);
free(tmp);
}
void freeTreeNode(treeNode* tmp)
{
if (tmp->next_possible_positions == NULL)
free(tmp);
else
{
freeTreeNodeListCell(tmp->next_possible_positions);
}
}
But as always, when trying to free memory, I receive dozens of warnings.
How can I free this huge tree without getting any errors? What is wrong with my program?
Big thanks in advance!
The existing freeTreeNode function has a memory leak:
void freeTreeNode(treeNode* tmp)
{
if (tmp->next_possible_positions == NULL)
free(tmp);
else
{
freeTreeNodeListCell(tmp->next_possible_positions);
// Memory leak here. `tmp` has not been freed.
}
}
Rather than repeating the call free(tmp), the function can be restructured as follows to be more like freeTreeNodeListCell:
void freeTreeNode(treeNode* tmp)
{
if (tmp->next_possible_positions != NULL)
{
freeTreeNodeListCell(tmp->next_possible_positions);
}
free(tmp);
}
The freeTreeNode and freeTreeNodeListCell functions are mutually recursive. freeTreeNode could be changed to an iterative function that subsumes freeTreeNodeListCell by "flattening" the tree into a list of treeNodes and a list of treeNodeListCells as it goes:
void freeTreeNode(treeNode* node)
{
treeNodeListCell *cell = NULL;
treeNodeListCell **endCell = NULL;
while (node || cell)
{
if (!cell)
{
endCell = &cell;
}
if (node)
{
*endCell = node->next_possible_positions;
while (*endCell)
{
endCell = &(*endCell)->next;
}
free(node);
node = NULL;
}
while (!node && cell)
{
treeNodeListCell *tmp = cell;
node = cell->node;
cell = cell->next;
free(tmp);
}
}
}
As a more profound change, the data structure could be simplified by merging treeNodeListCell into treeNode so that there are fewer types to worry about and to reduce the number of memory allocations required to hold the tree:
typedef struct _treeNode
{
chessPos position;
struct _treeNode *next_possible_positions;
struct _treeNode *node;
} treeNode;
That turns it into a sort of binary tree turned on its side, where next_possible_positions points across to the siblings, and node points down to the children.
That would make the freeTreeNode function simpler. Recursive version:
void freeTreeNode(treeNode *node)
{
if (node)
{
freeTreeNode(node->next_possible_positions);
freeTreeNode(node->node);
free(node);
}
}
Iterative version:
void freeTreeNode(treeNode *node)
{
treeNode **end = &node;
treeNode *tmp;
while (*end)
{
end = &(*end)->next_possible_positions;
}
while (node)
{
*end = node->node;
while (*end)
{
end = &(*end)->next_possible_positions;
}
tmp = node;
node = node->next_possible_positions;
free(tmp);
}
}
I am a new C99 programmer and want the help of the community on this one.
I wrote the following function which receives two pointers for a node (Or simply Node) and a pointer to a pointer to node (Or *Node) an merges them together into one sorted Node.
This is Given:
typedef struct node_t {
int x;
struct node_t *next;
} *Node;
typedef enum {
SUCCESS = 0,MEMORY_ERROR, EMPTY_LIST, UNSORTED_LIST, NULL_ARGUMENT,
} ErrorCode;
int getListLength(Node list);
bool isListSorted(Node list);
This is the code I wrote:
ErrorCode mergeSortedLists(Node list1, Node list2, Node *merged_out)
{
if (merged_out==NULL)
return NULL_ARGUMENT;
if (list1==NULL || list2==NULL)
return EMPTY_LIST;
if (!isListSorted(list1) || !isListSorted(list2))
return UNSORTED_LIST;
Node ptr=*merged_out;
int list1_len=getListLength(list1),list2_len=getListLength(list2);
for (int i=0;i<list1_len+list2_len;i++)
{
int min=0;
if (list1!=NULL && (list2==NULL || (list2!=NULL && list1->x<=list2->x))){
min = list1->x;
list1=list1->next;
}
else{
min=list2->x;
list2=list2->next;
}
ptr->x=min;
if (i==list1_len+list2_len-1){
ptr->next=NULL;//The next for the last Node should be Null
continue;
}
ptr->next=malloc(sizeof(*ptr));
if (ptr->next==NULL){
//We should Free all previosly allocated memory
//except for the first node since it was not allocated via malloc
return MEMORY_ERROR;
}
ptr=ptr->next;
}
ptr=NULL;
return SUCCESS;
}
But after reviewing my code I was told it has a lot of code duplications (more precisely inside he for loop) which should be corrected by using external functions, do u notice any code duplications? and how to fix that, any ideas?
I am trying to implement an inorder traversal that returns an array with the traversed values. In my recursive approach, I am trying to use realloc() function to modify the size of the array and store the result. However, I am getting the following error:
realloc(): invalid next size.
Following is my code:
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
};
void inorder(struct TreeNode *root, int *res, int *returnSize)
{
if(root == NULL)
return;
//if left node present, traverse left
inorder(root->left,res,returnSize);
// add node to array
res[(*returnSize)]=root->val;
(*returnSize)++;
int *temp = realloc(res,sizeof(int)*(*returnSize));
res = temp;
//if right node present, traverse right
inorder(root->right,res,returnSize);
}
/**
* Return an array of size *returnSize.
* Note: The returned array must be malloced, assume caller calls free().
*/
int* inorderTraversal(struct TreeNode* root, int* returnSize)
{
//check if root == null
if(root == NULL)
{
return root;
}
//malloc result array to return
int *res = (int *)malloc(sizeof(int)*(*returnSize));
//start inorder parsing
inorder(root, res, returnSize);
return res;
}
There are multiple problems:
the reallocated value for res is not passed back to the caller. You should pass a pointer to res instead of its value or return the newly allocated pointer.
returnSize is an output variable, you should initialize it to 1, or better to 0 and reallocate the array before storing the node value.
you should handle potential memory allocation failures.
Here is a corrected version:
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
};
int *inorder(struct TreeNode *root, int *res, int *returnSize) {
if (root != NULL) {
//traverse the left tree
res = inorder(root->left, res, returnSize);
if (returnSize >= 0) {
// add node to array
int *temp = realloc(res, sizeof(int) * (*returnSize) + 1);
if (temp == NULL) {
free(res);
*returnSize = -1;
res = NULL;
} else {
res = temp;
res[(*returnSize)++] = root->val;
//traverse the right tree
res = inorder(root->right, res, returnSize);
}
}
}
return res;
}
/**
* Return an array of size *returnSize.
* Return NULL and *returnSize=0 for an empty tree.
* Return NULL and *returnSize<0 for memory allocation failure.
* Note: The returned array is malloced, the caller must call free().
*/
int *inorderTraversal(struct TreeNode *root, int *returnSize) {
int *res = NULL;
*returnSize = 0;
return inorder(root, res, returnSize);
}
You almost certainly have memory corruption elsewhere in your code--this code looks good to me (well, apart from not testing the return from realloc() for NULL, but that would just cause you to lose data, not get the error you are seeing). If you can run valgrind on your program it will probably point you to the problem.
#include <stdio.h>
#include <malloc.h>
typedef struct Node {
int value; //4
struct Node* next; //4
}Node;
Node *create();
void add();
void del();
void search();
Node *create(int v) {
Node *first;
first = (Node *)(calloc(1,sizeof(*first)));
first->value = v;
first->next = NULL;
return first;
}
void add(Node **head,int v) {
Node *p;
p = (Node *)(calloc(1,sizeof(*p)));
p->value = v;
p->next = *head;
*head = p;
}
void search(Node *head) {
Node *p;
p=head;
while(p != NULL) {
printf("address is %d;value address is %d;next address is %d;next content is %d\n",p,&(p->value),&(p->next),p->next);
p = p->next;
}
}
int main() {
Node *head;
head = create(0);
add(&head,1);
add(&head,2);
add(&head,3);
search(head);
}
sizeof(Node) == 8, but why is every node's size in the heap is 16 bytes? thinks
(my system is 32bit).
struct node is 4bytes + 4bytes = 8bytes.
The nodes sizes aren't 16 bytes, it's just that malloc() chooses to skip 8 bytes of memory for some reason, likely for its own bookkeeping. If you want to conserve memory, do few large allocations, not many small ones, or else the bookkeeping overhead can cost quite a lot.
well, even if the memory allocated between calls to calloc() was continuous for you program (which you cannot make sure), don't forget that the lib c has 'private' data stored in the hunk of memory you allocated.
usually there is a header like:
struct hdr
{
size_t size; /* Exact size requested by user. */
unsigned long int magic; /* Magic number to check header integrity. */
struct hdr *prev;
struct hdr *next;
__ptr_t block; /* Real block allocated, for memalign. */
unsigned long int magic2; /* Extra, keeps us doubleword aligned. */
};
(code from)
You may see that the block actually the buffer of data that you'll get when calling malloc()/calloc(), is surrounded by a lot of extra data (ok, here is special case for debug, thus there are probably extra magics).
The errors involved in your code were logic errors related to the various list functions. When you have a create function, that functions job is to allocate memory for the node and assign any values required. It does not worry about which node it is dealing with.
Conversely, your add function does NOT allocate anything, it simply calls create to handle that work and then its job is merely properly wiring pointers and next->pointers to the proper node.
Since you are dealing with a head node that contains data, you have 3 possible conditions for add; (1) when head is NULL; (2) when head->next is NULL; and (3) all remaining additions.
Putting those pieces together and adding a print function, your code could look like the following:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int value; //4
struct Node* next; //4
} Node;
/* function prototypes */
Node *create (int v);
void add (Node **head, int v);
void del ();
void search (Node *head);
void printvalues (Node *head);
int main (void) {
Node *head = NULL;
// head = create(0);
add (&head,0);
add (&head,1);
add (&head,2);
add (&head,3);
printf ("\nsearching:\n\n");
search (head);
printf ("\nprinting:\n\n");
printvalues (head);
return 0;
}
/* create - only creates nodes */
Node *create (int v)
{
Node *new;
new = calloc (1, sizeof *new);
new->value = v;
new->next = NULL;
return new;
}
/* add does NOT create - only handles wiring */
void add (Node **head, int v)
{
Node *new = create (v);
if (!*head) {
*head = new;
return;
}
Node *p = *head;
while (p && p->next)
p = p->next;
if (!(*head)->next)
(*head)->next = new;
else
p->next = new;
}
void search(Node *head)
{
Node *p = head;
while (p != NULL) {
printf (" address is %p; next address is %p;\n", p, p->next);
p = p->next;
}
}
void printvalues (Node *head)
{
Node *p = head;
unsigned cnt = 0;
while (p != NULL) {
printf (" node[%2u] value: %d\n", cnt++, p->value);
p = p->next;
}
}
Output
$ ./bin/dbgllmess
searching:
address is 0x1acf010; next address is 0x1acf030;
address is 0x1acf030; next address is 0x1acf050;
address is 0x1acf050; next address is 0x1acf070;
address is 0x1acf070; next address is (nil);
printing:
node[ 0] value: 0
node[ 1] value: 1
node[ 2] value: 2
node[ 3] value: 3
Note: you are responsible for freeing the memory allocated when it is no longer needed. Let me know if you have any questions.
Regarding the real question "why is every node's size in the heap is 16 bytes?"
Well, you can't expect that one memory block will lay exactly at the end of where the previous memory block sits. you can't assume anything about how the heap is managed intenally. two blocks can sit in a gigabyte distance from one another even if they allcoated consequently with malloc.
On Windows , In order for the heap to keep track of the memory blocks allocated, each block gets few more bytes to hold meta-data of the memory block. this is called "Heap Entry", and it is probably why your blocks are a bit bigger.
but again, you can't assume anything of the blocks - positioning in the heap anyway.
This question already has an answer here:
C Linked List valgrind Invalid Read of Size
(1 answer)
Closed 8 years ago.
My understanding is that for every malloc we should free before we exit. Based on valgrind report, I do not have a leak. That said, valgrind is reporting that this code has an error: Address 0x402613c is 4 bytes inside a block of size 8 free'd
For brevity, below is just snips of portions of linked list code that shows the node type and sections of code where I malloc or free the node.
typedef struct node
{
int n;
struct node* next;
}
node;
// global variable for the head of the list
node* head = NULL;
int main(void)
{
// user menu
while (true)
{
printf("Please choose an option (0, 1, 2): ");
int option = GetInt();
switch (option)
{
// quit
case 0:
free_nodes(head);
printf("Goodbye!\n");
return 0;
// snipped: code that calls insert and print functions
bool insert_node(int value)
{
// create new node
node* new_node = malloc(sizeof(node));
if (new_node == NULL)
{
return false;
}
// snipped: some code that adds nodes to linked list
}
/**
* Frees all of the nodes in a list upon exiting the program.
*/
void free_nodes(node* list)
{
// initialize pointer
node* curr_node = head;
// initialize variable for end of list
bool is_end = false;
// free nodes
while (!is_end)
{
// if an empty list, free node and exit
if (curr_node->next == NULL)
{
free(curr_node);
is_end = true;
}
// else free node list until end of list if found
else
{
free(curr_node);
curr_node = curr_node->next;
}
}
}
The error is telling you that you're using a pointer to freed memory after you freed it:
void *m = malloc(8);
char *s = m + 4;
free(m);
*s = 29; // This would generate that warning.
int c = *s; // This would also generate that warning.
And, actually looking at your code, it is almost as blatant as the example above (as BLUEPIXY points out in his comment):
free(curr_node);
curr_node = curr_node->next;
Fix:
node *next = curr_node->next;
free(curr_node);
curr_node = next;