Designing a binary tree structure from scratch in C I'm a beginner and self learning programming students. While learning binary tree data types, for the sake of understanding graph theory and other interesting programming problems, I've writen the below implementation. Would you please suggest if there's anything wrong or either this can be improved. 


It may seem reinventing the wheel, as there's a nice STL in C++, but I do implement data structure and algos from scratch for the sake of a better understanding and visualization for me


Here's my code, and thanks in advance

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt; 

typedef struct tree {
      int value;

      struct tree *left_child;
      struct tree *right_child;
} bin_tree; 

void create_tree(int value, bin_tree **root);
void print_tree(bin_tree *root);
void free_mem(bin_tree *root);


int main() {
    bin_tree *root;

    root = (bin_tree *) malloc (sizeof(bin_tree));
    root = NULL;



    int val;
    while (scanf("%d", &amp;val) != EOF) {
           create_tree(val, &amp;root);
    }

    printf("root : %d\n", root-&gt;value);
    print_tree(root);
    free_mem(root);
    //printf("root: %d\n", root-&gt;value);
    return 0;
   }

void create_tree(int val, bin_tree **root) {
     if (*root == NULL) {
        bin_tree *cache = (bin_tree *) malloc(sizeof(bin_tree));
        cache-&gt;value = val;
        cache-&gt;left_child = NULL;
        cache-&gt;right_child = NULL;
        *root = cache;
     }
    /*this tree is built avoiding duplicates*/
   else if(val &lt; (*root)-&gt;value){ create_tree(val, &amp;(*root)-&gt;left_child);}
   else if(val &gt; (*root)-&gt;value){ create_tree(val, &amp;(*root)-&gt;right_child);}
  }



  void print_tree(bin_tree *root) {
       if (root != NULL) {
           print_tree(root-&gt;left_child);
           print_tree(root-&gt;right_child);
           printf("%d ", root-&gt;value);
         }
       }

   void free_mem(bin_tree *root) {
        if (root) {
           free_mem(root-&gt;left_child);
           free_mem(root-&gt;right_child);
           free(root);
   }
 }
Here are some things that may help you improve your code.

Don't leak memory

The main routine begins with these two curious lines of code:

root = (bin_tree *) malloc (sizeof(bin_tree));
root = NULL;


That's a guaranteed memory leak because we no longer have any way to refer to the memory allocated by malloc.  Since your create_tree function will automatically allocate space for the root node, I'd change that to this, combining declaration and initialization:

bin_tree *root = NULL;


Check return values and handle errors

The code calls malloc but never checks for error return values.  This is a serious problem that must be addressed.  Also, scanf can return EOF if there was an error, but that condition is neither checked nor handled.  

To be more precise, the way that the underlying operating system lets a program know that it cannot allocated the requested memory is by returning NULL from a call to malloc.  Robust programs should always check for that condition before using the returned value as a pointer or they will risk a crash by dereferencing a NULL pointer.  

Similarly, scanf returns the number of arguments successfully scanned.  In your case it should be 1 because each call is scanning one integer value.  If it's anything other than 1, it's an indication of a problem that should probably be handled gracefully by the program, perhaps by emitting a message to the user that only integer values are allowed and asking again.

Use "in-order" tree traversal

The binary tree you've constructed maintains the order of entries, so to take advantage of this, we should use in-order.  It's as simply as changing the order of two lines of code so the print_tree code looks like this:

void print_tree(bin_tree *root) {
    if (root != NULL) {
        print_tree(root-&gt;left_child);
        printf("%d ", root-&gt;value);
        print_tree(root-&gt;right_child);
    }
}


So for example, when I feed the program this input:


  10 5 33 2 18 17 15 20 22 1 8


The program then constructs this tree:



And an in-order traversal produces this output:


  1 2 5 8 10 15 17 18 20 22 33 


Put each statement on a single line

It detrimental to the readability of your code to put multiple things one the same line. So instead of this:

else if(val &lt; (*root)-&gt;value){ create_tree(val, &amp;(*root)-&gt;left_child);}


I would recommend writing this:

else if (val &lt; (*root)-&gt;value) { 
    create_tree(val, &amp;(*root)-&gt;left_child);
}


Omit return 0

When a C or C++ program reaches the end of main the compiler will automatically generate code to return 0, so there is no need to put return 0; explicitly at the end of main.  

Note: when I make this suggestion, it's almost invariably followed by one of two kinds of comments:  "I didn't know that." or "That's bad advice!"  My rationale is that it's safe and useful to rely on compiler behavior explicitly supported by the standard.  For C, since C99; see ISO/IEC 9899:1999 section 5.1.2.2.3:


  [...] a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument; reaching the } that terminates the main function returns a value of 0.


For C++, since the first standard in 1998; see ISO/IEC 14882:1998 section 3.6.1:


  If control reaches the end of main without encountering a return statement, the effect is that of executing return 0;


All versions of both standards since then (C99 and C++98) have maintained the same idea.  We rely on automatically generated member functions in C++, and few people write explicit return; statements at the end of a void function.  Reasons against omitting seem to boil down to "it looks weird".  If, like me, you're curious about the rationale for the change to the C standard read this question.  Also note that in the early 1990s this was considered "sloppy practice" because it was undefined behavior (although widely supported) at the time.  

So I advocate omitting it; others disagree (often vehemently!)  In any case, if you encounter code that omits it, you'll know that it's explicitly supported by the standard and you'll know what it means.