Beginning C BST implementation I'd really appreciate if I could get some feedback on the following code with regard to security, efficiency and possible uncaught errors. Personally I feel the printAndCleanString and friendlyLookup functions combined are very messy but I don't know how to fix them. 

In particular I would love feedack on how to more cleanly and efficiently return strings. 

#include &lt;stdio.h&gt;
#include &lt;malloc.h&gt;
#include &lt;mem.h&gt;

struct bstNode {
    int val;
    struct bstNode *left;
    struct bstNode *right;
};

void insert(struct bstNode **head, int val);

int lookup(struct bstNode **node, int val);

void printDFS(struct bstNode *head);

char *friendlyLookup(struct bstNode **node, int val);

void printAndCleanString(char *string);

int main() {
    struct bstNode *bstTree = NULL;
    insert(&amp;bstTree, 8);
    insert(&amp;bstTree, 5);
    insert(&amp;bstTree, 98);
    insert(&amp;bstTree, 2);
    insert(&amp;bstTree, 15);
    insert(&amp;bstTree, 65);
    insert(&amp;bstTree, 15);
    printDFS(bstTree);
    printf("\n");
    printAndCleanString(friendlyLookup(&amp;bstTree, 1));
    printAndCleanString(friendlyLookup(&amp;bstTree, 65));
}

void insert(struct bstNode **head, int val) {
    if (*head == NULL) {
        *head = malloc(sizeof(struct bstNode));
        if (*head == NULL) {
            printf("malloc failed!");
            return;
        }
        (*head)-&gt;val = val;
        (*head)-&gt;left = NULL;
        (*head)-&gt;right = NULL;
        return;
    }

    if (val &lt; (*head)-&gt;val) {
        return insert(&amp;(*head)-&gt;left, val);
    } else {
        return insert(&amp;(*head)-&gt;right, val);
    }
}

void printDFS(struct bstNode *head) {
    if (head-&gt;left != NULL) printDFS(head-&gt;left);
    printf("%d ", head-&gt;val);
    if (head-&gt;right != NULL) printDFS(head-&gt;right);
}

int lookup(struct bstNode **node, int val) {
    if (*node == NULL) {
        return -1;
    }
    if ((*node)-&gt;val == val) {
        return val;
    }
    if (val &lt; (*node)-&gt;val) {
        return lookup(&amp;(*node)-&gt;left, val);
    } else {
        return lookup(&amp;(*node)-&gt;right, val);
    }
}

char *friendlyLookup(struct bstNode **node, int val) {
    int result = lookup(node, val);
    char resultString[256];
    char numberString[256];
    sprintf(numberString, "%d", val);
    if (result &gt; -1) {
        sprintf(resultString, " is present in the bst\n");
    } else {
        sprintf(resultString, " is not present in the bst\n");
    }
    char *resultPointer = malloc(strlen(resultString) + strlen(numberString) + 1 * sizeof(char));
    if (resultPointer == NULL) {
        printf("Malloc error!");
        return NULL;
    }
    sprintf(resultPointer, "%s%s", numberString, resultString);
    return resultPointer;
}

void printAndCleanString(char *string) {
    printf(string);
    free(string);
}
#include &lt;mem.h&gt; should be properly #include &lt;string.h&gt;. The former is non-standard.
I prefer avoiding the duplication inherent in forward-declarations, so would put the definition before first use.
Unless, of course, I'm writing a header-file.
Remember that your friendlyLookup() can fail. And test for that.
It's a bad idea to name the type in a sizeof like in *head = malloc(sizeof(struct bstNode));. Changing it to *head = malloc(sizeof **head); is more resilient to change, obviously correct, and even shorter.
There are a few viable strategies for handling failure:


Ignoring it and hoping the program will crash. Even for toy-programs, that's extremely bad form.
Deteting it and aborting the program with an error-message. Often acceptable when resources are exceeded.
Fixing the failure. Often not possible, or at least not at that place.
Reporting the failure to the caller and letting them deal with it. The preferred method, especially for library-code.


You are instead doing a mixture: Printing an error-message (part of option 2) and then pretending you succeeded. That's a really bad combo.
Learn to love the ternary operator condition ? true-case : false-case. It would often simplify your code.


Applying some of the above:

void die(char* msg) {
    fprintf(stderr, "%s", msg);
    abort();
}

void insert(struct bstNode **head, int val) {
    if(!*head) {
        *head = malloc(sizeof **head);
        if(!*head)
            die("malloc failed!");
        **head = (struct bstNode){.val = val};
        return;
    }
    insert(val &lt; (*head)-&gt;val ? &amp;(*head)-&gt;left : &amp;(*head)-&gt;right, val);
}



if (head-&gt;left != NULL) is exactly the same as if (head-&gt;left).
In friendlyLookup() you are copying one of two string-literals into a (far too big) array, just to copy it again. Why? Use a pointer.

const char* resultString = result &gt; -1 ? " is present in the bst\n" : " is not present in the bst\n";

Also, numberString is far too big, but whatever.
printAndCleanString is a curious name. If such a utility-function makes sense, it should be "free" instead of "clean".
If you want to output a string, don't give it as format-string to printf(), but as an argument. Make it:

printf("%s", string);