Split function using C and dynamic memory allocation I have programmed a function to split strings, and it gives the expected output.
I am looking forward to write better code and I was told here is a good place to start.
Here's my program:
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

char **split(char *str) {
    int str_length = 0;
    int i = 0;
    int separator_count = 0;
    while (str[i] != '\0') {
        if (str[i] == ' ') {
            separator_count++;
        }
        i++;
    }

    char **word_array;

    word_array = malloc((separator_count + 2) * sizeof(char *));  

    int word_len = 0;
    int separator_index = 0;
    int b = 0;                                     //to iterate over &quot;str&quot;
  
    for (int a = 0; a &lt; (separator_count + 2); a++) {
        word_len = 0;
        while (str_length &lt; strlen(str) + 1) {
            str_length++;

            if (str[b] == ' ' || str[b] == '\0') {
                separator_index = b;
                word_array[a] = malloc(word_len * sizeof(char));
                int word_depth = 0;
                for (int c = (separator_index - word_len); c &lt; separator_index; c++) {
                    chrctr = str[c];
                    word_array[a][word_depth] = str[c];
                    word_depth++;
                }
                word_array[a][word_len] = '\0';         //terminate found and stored word with null charachter
                word_len = 0;                           //reset word length counter to 0
                b++;                                    //skip to next charachter
                break;                                  // break to go to next index of word_array
            }
            word_len++;
            b++;
        }
    }
    word_array[separator_count + 2] = NULL;
    return word_array;
}

int main() {
    char s[] = &quot;A complete toolkit for building search into your product.&quot;;  //test string
    char **ss = split(s);
    for (int i = 0; i &lt; sizeof(ss); i++) {        //here is the problem, and doing sizeof(ss)/sizeof(ss[0])=1 !!
        for (int j = 0; j &lt; strlen (ss[i]); j++) {
            printf(&quot;%c&quot;, ss[i][j]);
        }
        printf (&quot;\n&quot;);
    }
}

Please comment with any advice or remarks on how to make this better.
Design: Code should explain cases

Double space: &quot;abc  xyz&quot; --&gt; Is that to be 2 or 3 tokens?
Leading space: &quot; abc xyz&quot; --&gt; Is that to be 2 or 3 tokens?
Trailing space: &quot;abc xyz &quot; --&gt; Is that to be 2 or 3 tokens?

Design : Generalization
split() only considers ' '.  Maybe all white-spaces, '\t', '\n', ...?
Or pass into the function  a list of separators: split(char *str, const char *separators)
Design: const
As data referenced by str does not change, consider char **split(const char *str) for greater applicability and self documentation.
Bug: Insufficient memory
// word_array[a] = malloc(word_len * sizeof(char));
word_array[a] = malloc((word_len + 1u) * sizeof(char));
...
word_array[a][word_len] = '\0';

Bug: Writing outside allocation
word_array = malloc((separator_count + 2) * sizeof(char *));  
...
word_array[separator_count + 2] = NULL; //OOPS!

// I suspect OP wanted  
word_array[separator_count + 1] = NULL;

Allocate to the size of the reference object, not the type
// word_array = malloc((separator_count + 2) * sizeof(char *)); 
word_array = malloc(sizeof *word_array * (separator_count + 2u)); 


// word_array[a] = malloc(word_len * sizeof(char));
word_array[a] = malloc(sizeof (word_array[a][0] * word_len);

It is easier to code right, review and maintain.
Leading with the widest types in the multiplication prevents overflow - though that is not so important in this case.
Robust code checks allocation success
ptr = malloc(sizeof *ptr * n);
if (ptr == NULL &amp;&amp; n &gt; 0) {
  HandleOutOfMemory(); // Some user code
}

Clean-up allocations
main() called split(s) which allocates, but failed to call a matching free().  Not much concern with main() as code ends anyways, but good practice.
Minor: int word_len insufficient for large strings
// int word_len 
size_t word_len