cs50 pset5 unload problem - memory leakage - c

I am trying to solve the cs50 pset5. I am using a tries method.
I can insert word into the tries successfully. However, when i unload the memory, it fails. I am so stuck at the unload problem for a few days.
When I try the unload function, it stated that Erorr Message: double free or corruption (!prev): 0x000000000205d010 ***
It is probably due to my unload function, but i have drawn out the logic. It seems fine to me. Anyone has any idea where to amend?
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#define LENGTH 45
#define SIZE_OF_CHILD 27
typedef struct Node {
bool is_word;
struct Node* child[SIZE_OF_CHILD];
} Node;
Node* root;
Node* temp;
Node* create_node(Node* node);
void test();
int cal_key(char c);
Node* insert(const char* word);
void unload(Node* node);
int main() {
root = malloc(sizeof(Node));
if (root == NULL) {
exit(0);
}
root = create_node(root);
temp = malloc(sizeof(Node));
if (temp == NULL) {
exit(0);
}
test();
}
// **************** function to create a node *******************
Node* create_node(Node* node) {
node->is_word = false;
for (int i = 0; i < SIZE_OF_CHILD; i++) {
node->child[i] = NULL;
}
return node;
}
//************* calculate the key value ************
// Assume that the input is in lower case
int cal_key(char c) {
if (isalpha(c)) {
if (islower(c)) {
return c - 'a';
}
else {
return c + 32 -'a';
}
}
else {
return SIZE_OF_CHILD - 1;
}
}
//*************** function to insert an item in the the node ***********
Node* insert(const char* word) {
int str_len = strlen(word);
temp = root;
int key;
for (int i = 0; i < str_len; i++) {
key = cal_key(word[i]);
if (temp->child[key] == NULL) {
Node* node = malloc(sizeof(Node));
if (node == NULL) {
fprintf(stderr, "Error in creating node\n");
exit(0);
}
node = create_node(node);
temp->child[key] = node;
}
temp = temp->child[key];
}
temp->is_word = true;
return root;
}
//***************** function to unload a function ********************
void unload(Node* node) {
// This is to find the last node
for (int i = 0; i < SIZE_OF_CHILD; i++) {
if (node->child[i] != NULL) {
unload(node->child[i]);
}
free(node);
}
}
void test() {
root = insert("Peter");
unload(root);
}

Related

Problem searching in my Binary Search Tree

Problem is function bin_search. it works steady on function insert. However, it gets frozen on function search. I think if it's fine on insert, it should be fine on search, but it isn't. Here is my code...
"bst.h":
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node {
int key;
void *data;
struct Node *left, *right;
void (*destroy)(void *data);
} node;
typedef struct Tree {
node *head;
char name;
} tree;
#define key(node) node->key
#define data(node) node->data
#define left(node) node->left
#define right(node) node->right
#define destroy(node) node->destroy
#define tree_head(tree) tree->head
"functions.c":
#include "bst.h"
int bin_search(node *curr, int key, int cnt, node **found) {
cnt++; printf("cnt+\n");
if (curr == NULL) {
return -1;
} else if (curr->key == key) {
printf("curr_key = key\n"); return cnt;
}
if (curr->key < key) {
printf("curr_key < key\n");
if (curr->right == NULL) {
*found = curr;
return -(cnt + 1);
}
return bin_search(curr->right, key, cnt, found);
} else {
printf("curr_key > key\n");
if (curr->left == NULL) {
*found = curr;
return -(cnt + 1);
}
return bin_search(curr->left, key, cnt, found);
}
}
int insert(tree *root, int key, void *data, void (*destroy)(void *data)) {
if (root->head == NULL) {
node* new_node = (node *)malloc(sizeof(node));
left(new_node) = NULL; right(new_node) = NULL; destroy(new_node) = destroy; key(new_node) = key; data(new_node) = data;
tree_head(root) = new_node;
printf("created first node\n"); return 1;
}
int cnt; node **found;
if ((cnt = bin_search(root->head, key, 0, found)) < 0) {
node* new_node = (node *)malloc(sizeof(node));
left(new_node) = NULL; right(new_node) = NULL; destroy(new_node) = destroy; key(new_node) = key; data(new_node) = data;
if ((*found)->key < key) {
(*found)->right = new_node;
} else {
(*found)->left = new_node;
}
printf("created a node at %d\n", -cnt); return 1;
} else {
printf("already exists in tree"); return -1;
}
}
int search(tree *root, int key, void **data) {
if (root->head == NULL) {
printf("tree is empty\n"); return -1;
}
int cnt; node **found;
if ((cnt = bin_search(root->head, key, 0, found)) < 0) {
return -1;
} else {
if ((*found)->key < key) {
*data = (*found)->right->data;
} else {
*data = (*found)->left->data;
}
return cnt;
}
}
"main.c":
#include "bst.h"
#define MAX_NUM 8
#define MAX_LEGNTH 200
int main() {
// create a tree
tree root; root.head = NULL; root.name = 'a';
FILE *inpt = fopen("list.txt", "r"); char buffer[MAX_LEGNTH];
int count = 0;
while (fgets(buffer, MAX_LEGNTH, inpt) != NULL) {
printf("adding: %d\n", atoi(buffer)); insert(&root, atoi(buffer), buffer, NULL);
count++;
}
fclose(inpt);
int result; void **found;
result = search(&root, 2, found); printf("%d\n", result); // problem in here!!
return 0;
}
what is the problem with my 'search' function. I can't find it.
Besides the utterly non-standard use of sizeof(void), you are not providing a correct out-parameter to search. The point of the found argument is to receive the node pointer if the prospect key was discovered. This...
int cnt;
node **found; // <== LOOK HERE
if ((cnt = bin_search(root->head, key, 0, found)) < 0) {
is not the way to do that. It should be done like this:
int cnt;
node *found = NULL;
if ((cnt = bin_search(root->head, key, 0, &found)) < 0) {
// ^^^^^^
and all references to found thereafter should be through found->, not (*found)->
This mistake is made in three different places in your code. The last one is semi-broken, but still broken nonetheless.
void **found = (void *)malloc(sizeof(void));
int result = search(&root, 2, found);
printf("%d\n", result);
That should use this:
void *found = NULL;
int result = search(&root, 2, &found);
printf("%d\n", result);
Whether the rest of your code is broken I cannot say, and frankly we're not in the business of being an online-debugger. Use your local debugger tools; that's what they're for. But the items listed above are definitely a problem.

How to solve exception thrown in traversing forest

Question: Compute numbers of leaves in forest. Promblem: After debugging and printing a part of data, when I traverse printf("%d ", node->data);, incurred in a runtime error, that is, exception thrown: read access violation.
MainFunc.c
#include "AllFun.h"
int main(int argc, char* argv[])
{
CsNode* tree = (CsNode*)malloc(sizeof(CsNode));
if (tree) {
tree->firstchild = NULL;
tree->nextsibling = NULL;
CreateTree(&tree);
preOrder(tree);
int leaves = CountForestLeaves(tree);
printf("leaves: %d", leaves);
}
return 0;
}
AllFun.h
#include <stdio.h>
#include <stdlib.h>
typedef struct CsNode {
struct CsNode* firstchild;
struct CsNode* nextsibling;
int data;
}CsNode;
void CreateTree(CsNode** node);
void preOrder(CsNode* node);
int CountForestLeaves(CsNode* tree);
OtheFunc.c
#include "AllFun.h"
void CreateTree(CsNode** node)
{
int data;
printf("please input data: ");
scanf_s("%d", &data);
if (data != -1) {
*node = (CsNode*)malloc(sizeof(CsNode));
(*node)->data = data;
(*node)->firstchild = NULL;
(*node)->nextsibling = NULL;
CreateTree(&(*node)->firstchild);
CreateTree(&(*node)->nextsibling);
}
}
void preOrder(CsNode* node)
{
if (node != NULL) {
printf("%d ", node->data);
preOrder(node->firstchild);
preOrder(node->nextsibling);
}
}
int CountForestLeaves(CsNode* tree)
{
if (tree == NULL)
return 0;
if (tree->firstchild == NULL)
return 1 + CountForestLeaves(tree->nextsibling);
else {
return CountForestLeaves(tree->firstchild) + CountForestLeaves(tree->nextsibling);
}
}

How can I get a non-empty binary tree and print it?

I built three files, which includes MainFunc.c, AllFun.h, and OtheFunc.c.
The program happens runtime error, which print nothing. However, I need it output a tree as previous order.
I guess the problem may be that I built an empty tree, but I can't solve it.
MainFunc.c
#include "AllFun.h"
int main(int argc, char* argv[])
{
int nums[MaxSize] = { 0 };
printf("Enter value of root node: ");
for (int i = 0; i < MaxSize; ++i) {
scanf_s("%d", &nums[i]);
}
TreeNode* root = create(nums, MaxSize);
preorder(root);
return 0;
}
AllFun.h
#include <stddef.h> // NULL
#include <stdlib.h>
#include <stdio.h>
#define MaxSize 10
typedef struct node {
int data;
struct node* lchild, * rchild;
} TreeNode;
TreeNode *create(int nums[], int n);
void preorder(TreeNode *root);
OtheFunc.c
#include "AllFun.h"
TreeNode* newNode(int v) {
TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));
if (node) {
node->data = v;
node->lchild = node->rchild = NULL;
return node;
}
}
void insert(TreeNode* root, int x)
{
if (root == NULL) {
root = newNode(x);
return;
}
if (root->data < x) {
insert(root->lchild, x);
}
else {
insert(root->rchild, x);
}
}
TreeNode *create(int nums[], int n)
{
TreeNode* root = NULL; // Build a empty root node
for (int i = 0; i < n; i++) {
insert(root, nums[i]);
}
return root;
}
void preorder(TreeNode* root)
{
if (root == NULL) {
return;
}
printf("%d ", root->data);
preorder(root->lchild);
preorder(root->rchild);
}
You have to pass the node as a pointer to pointer, then the function can change the pointer:
void insert(TreeNode** root, int x)
{
if (*root == NULL) {
*root = newNode(x);
return;
}
if ((*root)->data < x) {
insert(&(*root)->lchild, x);
}
else {
insert(&(*root)->rchild, x);
}
}
Call with insert(&root, nums[i]);:
https://ideone.com/nV5q1g

Having trouble creating an adjacency list

I am trying to represent a graph using an adjacency list, but I am currently struggling with it. For some reason the edges are getting assigned to the wrong vertexes and I can't figure out why. I step through the code and the first 3 vertex pairs are added just fine but for some reason on the 4th nothing works right and I end up creating multiple new edges and not even the values of them are correct. A sample input is below as well as the C code. Anyone know why this might be happening? Note that
void print_distance(vertex*, int);
int check_an_edge(edge*);
void free_head(vertex*);
have not been implemented but free_head is used to free the entire list
5
(2,3)
(1,4)
(1,3)
(3,4)
(4,5)
#include <stdio.h>
#include <stdlib.h>
#include "input_error.h"
#define VertexToSearch 1
typedef struct node {
int value;
struct node* nextedge;
} edge;
typedef struct node1 {
int vertexnumber;
int distance;
struct node* edge;
} vertex;
vertex* load_file(char*);
void create_vertex_list(vertex*, int);
void create_new_edge(int, int, vertex*);
void print_distance(vertex*, int);
int check_an_edge(edge*);
void free_head(vertex*);
enum error program_error;
int main(int argc, char** argv) {
vertex* array;
array = load_file(argv[1]);
free_head(array);
return 0;
}
vertex* load_file(char* filename) {
int count;
int vertex1;
int vertex2;
FILE* file = fopen(filename, "r");
if (file == NULL) {
printf("%s did not open", filename);
program_error = FILE_FAILED_TO_OPEN;
exit(program_error);
}
fscanf(file, "%d", &count);
vertex* head = malloc(sizeof(vertex)* count);
create_vertex_list(head, count);
for (int i = 0; i < count; i++) {
fscanf(file, "\n(%d,%d)", &vertex1, &vertex2);
create_new_edge(vertex1, vertex2, head);
}
fclose(file);
return head;
}
void create_vertex_list(vertex head[], int count) {
vertex *new_node;
for (int i = 0; i < count; i++) {
new_node = malloc(sizeof (vertex));
new_node->vertexnumber = i + 1;
new_node->edge = NULL;
new_node->distance = -1;
*(head +i)= *new_node;
}
}
void create_new_edge(int vertex1, int vertex2, vertex* head) {
edge* new = malloc(sizeof (edge));
edge* new1 = malloc(sizeof (edge));
new->value = vertex1;
new1->value = vertex2;
new->nextedge = NULL;
new->nextedge = NULL;
if ((head +vertex1 - 1)->edge == NULL) {
(head +vertex1 - 1)->edge = new1;
} else {
edge* temp = (head +vertex1 - 1)->edge;
while (temp != NULL) {
if (temp->nextedge == NULL) {
temp->nextedge = new1;
break;
} else {
temp = temp->nextedge;
}
}
}
if ((head +vertex2 - 1)->edge == NULL) {
(head +vertex2 - 1)->edge = new;
} else {
edge* temp = (head +vertex2 - 1)->edge ;
while (temp != NULL) {
if (temp->nextedge == NULL) {
temp->nextedge = new1;
break;
} else {
temp = temp->nextedge;
}
}
}
}
In your create_new_edge function in the second if-statement you try to add new1. I think it's a copy-paste bug and you should change it to new.
if ((head +vertex2 - 1)->edge == NULL) {
(head +vertex2 - 1)->edge = new;
} else {
edge* temp = (head +vertex2 - 1)->edge ;
while (temp != NULL) {
if (temp->nextedge == NULL) {
temp->nextedge = new1; // Change here new1 to new
break;
} else {
emp = temp->nextedge;
}
}
}

Inserting and Removing from Linked List

This is a hashtable implementation.
I have the insert kinda working but how do I return the linked list?
I know that the remove is not done yet but I understand the concept, my problem is returning the adjusted list.
I tried to make the hashtable a global variable but the programming would force when I ran it.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include <string.h>
struct node {
char * data;
struct node * next;
};
struct hashtable {
struct node ** table;
int size;
int nentries;
};
struct hashtable * hashtable_new(int size) {
struct hashtable * result;
result = malloc(sizeof(struct hashtable));
result -> size = size;
result -> nentries = 0;
result -> table = malloc(sizeof(struct node) * size);
int i = 0;
for (i = 0; i < result->size; i++) {
result->table[i] = NULL;
// result->table[i]->data = NULL;
}
return result;
}
unsigned hash_string(struct hashtable *this, char * str) {
unsigned hash = 0;
int i = 0;
for ( i = 0; str[i] != '\0'; i++ ) {
hash = hash * 37 + str[i];
}
//return hash;
return hash % this-> size;
}
void hashtable_free(struct hashtable * this) {
int i;
struct node *table_nodes, *current, *next;
for(i = 0; i<this->size; i++) {
table_nodes = this->table[i];
current = table_nodes;
while (current != NULL){
next = current->next;
free(current);
current = next;
}
this->table[i] = NULL;
}
free(&this->table);
free(&this->size);
free(&this->nentries);
free(this);
}
void hashtable_insert(struct hashtable * table, char * string) {
struct node * new_node;
unsigned index = hash_string(table, string);
if(table->table[index] == NULL) {
printf("\nIndex: %d", index);
new_node = malloc(sizeof(struct node));
new_node -> next = table->table[index];
new_node -> data = string;
printf("\nData: %s", new_node->data);
table -> table[index] = new_node;
table -> nentries++;
printf("\n");
} else {
new_node = malloc(sizeof(struct node));
new_node->data = string;
new_node->next = NULL;
struct node * current = table->table[index];
struct node * next;
int size = 1;
while (current != NULL) {
next = current->next;
//if(current->data == string){
//return;
//}
if(current-> next == NULL){
//last element in list
current->next = new_node;
table->nentries++;
size++;
printf("\nIndex: %d", index);
printf("\nSize: %d", size);
printf("\nData: %s", current->next->data);
printf("\n");
return;
}
current = next;
size++;
}
}
}
void remove_hash(struct hashtable * this, char * item) {
//unsigned index = hash_string(this, item);
}
int lookup(struct hashtable * this, char * item) {
struct node *temp;
unsigned int index = hash_string(this, item);
temp = this->table[index];
while(temp != NULL) {
// do something
printf("%s, ", temp->data);
if(temp->data == item) {
printf("found %s\n", temp->data);
}
temp = temp->next;
}
return 0;
}
void print(struct hashtable * this) {
int i = 0;
printf("\n Size %d \n", this->size);
if(this == NULL) {
printf("Please construct the hashtable");
return;
}
for (i = 0; i < this->size; i++) {
if(this->table[i] == NULL) {
printf("\n %d: <empty>", i);
} else {
printf("\n %d: %s ", i, this->table[i]->data);
if(this->table[i]->next != NULL) {
printf("%s ", this->table[i]->next->data);
}
}
}
}
int main(int argc, char **argv) {
//struct node *theNode;
struct hashtable *theHash;
theHash = hashtable_new(9);
hashtable_insert(theHash, "I");
hashtable_insert(theHash, "am");
hashtable_insert(theHash, "a");;
hashtable_insert(theHash, "fish");
hashtable_insert(theHash, "glub");
print(theHash);
hashtable_insert(theHash, "glub");
lookup(theHash, "I");
print(theHash);
//printf("\n\n\n");
hashtable_free(theHash);
//print(theHash);
return 0;
}
Since C doesn't let you pass by reference, you can try returning the hashtable then reassigning your variable with the result of hashtable_insert:
struct hashtable *hashtable_insert(struct hashtable *table, char *string) {
// awesome code here
return current;
}
And then call it with:
theHash = hashtable_insert(theHash, "Wow!");

Resources