Wait, do I read it right this code was not written just for practice? Unfortunately the actual problem was not stated. What expectations are there when it comes to the content of the string? How about spaces at the beginning, end, or multiple spaces between words?
The function is unusable. There is no indication how many words were found. It should either return a number or have the array NULL-terminated (or preferably both).
As was mentioned by someone else reallocs here are a non-starter. Apart from the issue of not checking for failed allocation, you copy data a lot.
Instead you can just traverse the string counting how many words are there, allocate appropriate table and have a second pass where you allocate + fill elements.
Except chances you don't even want to do that. Maybe source string is expected to be modifiable and all strings fried at one, in which case you can just have an array to substrings where you replace spaces with zeros in the original string.
It maybe you don't want that either, maybe you are fine enough with a pair addr + length for each string, who knows.
On to the code.
char **strsplit (char source)
char **strings = calloc(1, sizeof(char *));
int nStrings = 0, nChars = 0;
strings = calloc(2, sizeof(char));
Why? For an empty string?
while('\0' != *source)
Yoda-style comparison with no merit....
if(*source == ' ')
... followed by normal comparison on the next line.
nChars = 0;
strings = realloc(strings, (1 + nStrings) * sizeof(char *));
strings[nStrings] = calloc(2, sizeof(char));
strings[nStrings][nChars] = *source;
strings[nStrings][nChars + 1] = '\0';
strings[nStrings] = realloc(strings[nStrings], (2 + nChars) * sizeof(char));
This is barely readable and very inefficient.