Why in the first code any->next and root->next at the free_hashtable returns nil? If I print in the generate function, it does returns an address... So, as the *root is global, why I can't access it?
Also why in the second code when I recursive call a function that have a paramenter pointing to a global structure pointer (so I can navigate throught it), it just gives me the main address, if I try like function(any->next), the returned value is just the same as any not any->next.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
const int nodes = 27; // 26 letters + '.
int height = 3;
typedef struct hash_table
{
char word[46]; // 45 letters + NULL.
struct hash_table *next;
}
hash_table;
typedef struct trie
{
bool is_word;
struct trie *character[nodes];
hash_table *next;
}
trie;
trie *generate(int times);
void free_hashtable(trie *any, int times);
void free_hashtable2(hash_table *any);
void free_trie(trie *any);
trie *root;
int main(void)
{
// Generate a trie with a height specified in a variable
// and also allocate memory to the entire structure.
root = generate(height);
free_hashtable(root, height);
free_trie(root);
free(root);
return 0;
}
trie *generate(int times)
{
// Allocate memory to root, to character[i]
// and also change the access of character[i] to root.
// So in the second run, root would be equivalent to
// root->character[i].
root = malloc(sizeof(trie));
//printf("%p\n", root); HERE it gives me an address.
root->next = NULL;
if (times > 0)
{
for (int i = 0; i < nodes; i++)
{
// For every single pointer generates more nodes pointers.
root->character[i] = generate(times - 1);
}
}
else
{
for (int i = 0; i < nodes; i++)
{
// Set all remaining pointers to null
// as there aren't more arrays.
root->character[i] = NULL;
}
// Malloc for new structure.
root->next = malloc(sizeof(hash_table));
root->next->next = NULL;
}
// Return the address of root,
// so the root in the main function can point
// to the trie created.
return root;
}
void free_hashtable(trie *any, int times)
{
printf("%p\n", root->character[0]); // print nil, yet, if I print in the generate function,
// it does give me an address.
printf("%p\n", any->character[0]); // returns nil, but why?
// Shouldn't any = root? and then any->next = root->next?
for (int i = 0; i < nodes; i++)
{
if (times > 1)
{
free_hashtable(any->character[i], times - 1);
}
}
if (times == 1)
{
for (int i = 0; i < nodes; i++)
{
//Where root is root->character[i]->character[i]
if (any->character[i]->next->next != NULL)
{
free_hashtable2(any->character[i]->next);
}
free(any->character[i]->next);
}
}
return;
}
void free_hashtable2(hash_table *any)
{
if (any->next != NULL)
{
free_hashtable2(any->next);
free(any->next);
}
return;
}
void free_trie(trie *any)
{
for (int i = 0; i < nodes; i++)
{
if (any->character[i] != NULL)
{
// Calls function first so it can works backwards.
free_trie(any->character[i]);
free(any->character[i]);
}
}
return;
}
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct test
{
char word[15];
struct test *next;
}
test;
test *root;
test *generate(int times);
void free_dummy(test *any);
int main(void)
{
root = generate(3);
free_dummy(root);
free(root);
}
test *generate(int times)
{
root = malloc(sizeof(test));
strcpy(root->word, "dummy");
if (root == NULL)
{
return NULL;
}
if (times != 0)
{
root->next = generate(times - 1);
}
if (times == 0)
{
root->next = NULL;
}
return root;
}
void free_dummy(test *any) // Comes as root.
{
printf("%p\n", any); // any never updates to root->next, but any is pointing to root. Shouldn't any->next = root->next?
if (any->next != NULL)
{
free_dummy(any->next);
free(any->next);
}
return;
}
Thanks to everyone! All help is welcome!
You call the function generate()
recursively and two things happens you overwrite the global variable root = malloc(...)
in each call (leaking memory) and in the last call when when times == 0
you reset root->characters[i] = NULL.
I had to change nodes to a symbolic constant to get your code to compile, and changed height for consistency.
In generate()
use a local variable root
instead. Prefer passing a variable opposed to type to sizeof. I didn't fix it but you should check that malloc()
was successful.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define nodes 27 // 26 letters + '.
#define height 3
typedef struct hash_table {
char word[46]; // 45 letters + NULL.
struct hash_table *next;
} hash_table;
typedef struct trie {
bool is_word;
struct trie *character[nodes];
hash_table *next;
} trie;
trie *generate(int times) {
trie *root = malloc(sizeof *root);
root->next = NULL;
if(!times) {
for (int i = 0; i < nodes; i++)
root->character[i] = NULL;
root->next = malloc(sizeof *root->next);
root->next->next = NULL;
return root;
}
for (int i = 0; i < nodes; i++)
root->character[i] = generate(times - 1);
return root;
}
void free_hashtable2(hash_table *any) {
if (!any->next) return;
free_hashtable2(any->next);
free(any->next);
}
void free_trie(trie *any) {
for (int i = 0; i < nodes; i++) {
if (!any->character[i]) continue;
free_trie(any->character[i]);
free(any->character[i]);
}
}
void free_hashtable(trie *any, int times) {
printf("%p\n", (void *) any->character[0]);
for (int i = 0; i < nodes; i++)
if (times > 1)
free_hashtable(any->character[i], times - 1);
if (times == 1)
for (int i = 0; i < nodes; i++) {
if (any->character[i]->next->next)
free_hashtable2(any->character[i]->next);
free(any->character[i]->next);
}
}
int main(void) {
trie *root = generate(height);
free_hashtable(root, height);
free_trie(root);
free(root);
}
To me, the 3 different free functions is a code smell. Instead write one free function that does the "opposite" of your builder function generate()
.