Don't we have to "free" this "toReturn" variable?
Yes, eventually you'd want to free the memory after you're done with it.
I still couldn't find clear answer and I can't find a way to free it when I return it. Can someone explain it to me?
When you use the function you assign it to a new pointer, you can use this pointer, not only to access the memory block you returned, but also to free it, example:
int main()
{
    char** values = loadValues();
    
    // do something with values
    // don't need them anymore
    for (int i = 0; i < 5; i++){
        free(values[i]);
    }
    free(values);
}
Note that strncpy(toReturn[i], "string", i + 1); is likely not what you want, in each iteration you are copying only from 1 to 5 characters respectively, not the entire string, and more importantly, not the null terminator.
The third argument of strncpy should be the length of "string" plus 1 more byte for the null terminator, so 7 in this case. Alternatively, if want to copy only part of ther string, you have to null-terminate it yourself.
If the goal is to copy the entire string, you can let the compiler do that for you:
//...
toReturn = malloc(5 * sizeof(char *));
for (i = 0; i < 5; i++)
{
    toReturn[i] = strdup("string");  // duplicate string and store it in toReturn[i]
}
//...
Of course you still need to free it yourself like in the first situation.