Думайте об этом так:
char *temp2 = "foo";
char **temps;
temps[0] = temp2; // won't work
temps = &temp2; // ok
temp2 указывает на строку C.Вы можете указывать временные значения по адресу temp2, (& temp2), но вы не можете разыменовать временные значения (то есть временные значения [0]), если сначала не указали на что-то допустимое.Из вашего вопроса звучит так, как будто вы хотите сначала выполнить malloc () для массива char *.
Во втором и третьем случаях вы разыменовываете temps [0], предварительно не обращаясь к какой-либо допустимой ячейке памяти.Как уже указывалось, temp указывает на место для мусора.
Ваш первый случай работает, потому что вы разыменовываете split (), поэтому он дает вам символ *.