This is my first attempt at writing a library in C. I have only included tree creation and in-order traversal function for now, but will expand to have more functions soon. I have three files, tree.h
, tree.c
and test.c
. How can I improve code quality, what are your suggestions? My main concerns are:
- Optimizations - Is my code sufficiently optimized and is any more optimization possible?
- Memory leaks - Is there any scope for memory leaks?
- Readability
Below is the code for tree.h
#ifndef TREE_H
#define TREE_H
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#define null NULL
#endif
typedef struct tree_node {
int val;
struct tree_node *left, *right;
} TreeNode;
typedef struct tree {
TreeNode *root;
} Tree;
static int count_nodes_in_string(char *);
static char** word_break(char *string, int n);
static int convert_to_integer(char *);
static char *convert_to_string(int val);
static TreeNode *create_node(int);
static TreeNode *make_tree_helper(char **, int, int);
static void inorder_helper(TreeNode *, char **);
static void delete_helper(TreeNode *);
char* inorder(Tree *);
Tree *makeTree(char *);
void deleteTree(Tree *);
The code for tree.c
#include "tree.h"
#define delim ' '
static int count_nodes_in_string(char *string) {
int index = 0, count = 0;
while(string[index] != '\0') {
if(string[index] == delim) {
count++;
}
index++;
}
return count + 1;
}
static char** word_break(char *string, int number) {
int index = 0, count = 0, prev = 0;
char **words = (char **)malloc(sizeof(char*) * number);
while(string[index] != '\0') {
if(string[index] == delim) {
words[count] = (char *)malloc(sizeof(char) * (index - prev + 1));
strncpy(words[count], string + prev, index - prev);
words[count][index - prev] = '\0';
prev = index + 1;
count++;
}
index++;
}
//For last word.
words[count] = (char *)malloc(sizeof(char) * (index - prev + 1));
strncpy(words[count], string + prev, index - prev);
words[count][index - prev] = '\0';
return words;
}
static int convert_to_integer(char *number) {
int index = 0, result = 0;
while(number[index] != '\0') {
result = result * 10 + number[index] - '0';
index++;
}
free(number);
return result;
}
static char *convert_to_string(int val) {
int digits = log10(val) + 1, rem;
int index = digits - 1;
char *number_to_string = malloc((digits + 1) * sizeof(char));
if(number_to_string == null) {
printf("Error: Unable to allocate memory.");
exit(1);
}
while(val > 0) {
number_to_string[index] = (val % 10 + '0');
val = val / 10;
index--;
}
number_to_string[digits] = ' ';
return number_to_string;
}
static TreeNode *create_node(int val) {
TreeNode *node = malloc(sizeof(TreeNode));
if(node == null) {
printf("Error: Unable to allocate memory.");
exit(1);
}
node->val = val;
node->right = node->left = null;
return node;
}
static TreeNode *make_tree_helper(char **words, int n, int i) {
if(i >= n) {
return null;
}
if(strcmp(words[i], "N") == 0) {
return null;
}
TreeNode *root = create_node(convert_to_integer(words[i]));
root->left = make_tree_helper(words, n, 2 * i + 1);
root->right = make_tree_helper(words, n, 2 * i + 2);
return root;
}
static void inorder_helper(TreeNode *root, char **inorder_string) {
if(root) {
inorder_helper(root->left, inorder_string);
char *converted_integer = convert_to_string(root->val);
if(*inorder_string == null) {
*inorder_string = strdup(converted_integer);
}
else {
strcat(*inorder_string, converted_integer);
}
free(converted_integer);
inorder_helper(root->right, inorder_string);
}
return;
}
static void delete_helper(TreeNode *root) {
if(root) {
delete_helper(root->left);
delete_helper(root->right);
free(root);
}
return;
}
char* inorder(Tree *tree) {
char *inorder_string = null;
inorder_helper(tree->root, &inorder_string);
return inorder_string;
}
Tree *makeTree(char *string) {
Tree *tree = malloc(sizeof(Tree));
if(tree == null) {
printf("Error: Unable to allocate memory.");
exit(1);
}
int nodes = count_nodes_in_string(string);
char **words = word_break(string, nodes);
tree->root = make_tree_helper(words, nodes, 0);
return tree;
}
void deleteTree(Tree *tree) {
delete_helper(tree->root);
free(tree);
tree = null;
}
And the code for test.c
#include <stdio.h>
#include <string.h>
#include "tree.h"
static unsigned test_tree_lib(const char *, int, char *, char *);
#define TEST_BINARY_TREE(input, expected) failures += test_tree_lib(__FILE__, __LINE__, input, expected)
static unsigned test_tree_lib(const char *file, int line, char *input, char *expected) {
Tree *tree = makeTree(input);
char *inorder_traversal = inorder(tree);
int result = strcmp(inorder_traversal, expected);
printf("%s\n", inorder_traversal);
free(inorder_traversal);
deleteTree(tree);
return result == 0;
}
int main() {
unsigned failures = 0;
unsigned test = 3;
char test1[] = "1 2 3 4";
TEST_BINARY_TREE(test1, "4 2 1 3 ");
char test2[] = "4 2 6 1 3 5 7";
TEST_BINARY_TREE(test2, "1 2 3 4 5 6 7 ");
char test3[] = "50 30 60 5 20 45 70 N N N N N N 65 80";
TEST_BINARY_TREE(test3, "5 30 20 50 45 60 65 70 80 ");
printf("\n---------------- Tests completed ----------------\n");
printf("\n---------------- Total tests : %u ---------------\n", test);
printf("\n-------------- Successful tests : %u ------------\n", failures);
return failures > 0;
}