Вариант с "токенизацией" делит один единственный буфер на несколько Си строк, т.е. там просто записывается завершающий 0 вместо разделителей. Это быстро и довольно просто, ничего никуда не копируется, дополнительная память не выделяется. Но надо иметь ввиду, что используется один и тот же буфер и если вы его не аккуратно перезапишите (не важно по какому указателю на внутренние строки), то ваши строки "испортятся". Освобождая память под этим буфером надо, естественно, по указателю на начало буфера, а не по указателю на произвольную строку внутри буфера. Освободив буфер надо иметь ввиду, что все строки, содержащиеся в буфере то же освободились.
Вариант с выделением подстрок и генерацией массива строк - возможно проще, но достаточно медленный. Т.к. для каждой подстроки выделяется динамическая память и подстрока копируется в новое расположение. Каждую результирующую строку надо удалять отдельно, что то же добавляет накладных расходов.
Оба варианта имеют место быть. Выбирать надо тот, что больше ложится на вашу главную задачу, т.к. разделение строк, я думаю, это не самоцель, а некая подзадача.
Если же вам надо только "вывести подстроку", то можно просто искать позицию разделителя, с его помощью вычислять размер левой подстроки и используя printf("%*s", len, leftstr);
выводить левую подстроку. Дальше сохраняем указатель на начало правой подстроки, ищем от него следующий разделитель, то, что раньше было правой подстрокой становится левой, точно так же выводим и т.д. в цикле.
Вместо printf можно выводить так: cout << setw(len) << leftstr;