Так они не подряд идут. У них дистанция для первых двух - 112 байт. Далее 32. Упаковка. А ты что хотел? Чтоб бинарник был дырявый как сыр и имел 1 Гигабайт размером?
Неудивительно. Язык "C" вобщем плохо приспособлен для обработки текста. Семантика ASCIIZ-векторов такова что для того чтобы "что-то" куда-то вставить - надо: Замерять размер строки. Замерять размер вставляемой строки. Аллоцировать память. Скопировать старую строку в новое место с изменениями.
Модифицировать строку по месту... хм.. так себе идея. Я-бы не советовал. Делает код потенциально опасным. Все таки лучше чтобы строка была иммутабельной.
void * означает указатель на область памяти неизвестного типа. При разыменовании тебе надо будет
заранее знать что за зверь скрывается под этой памяти чтобы правильно интерпретировать результат.
В современном программировании безтиповые указатели - считается угрозой безопасности и большинство компилляторов выдают WARNING. При прочих равных условиях лучше void * не использовать а использовать ... ну например указатель на массив байт или на такую-же структуру s_list к примеру.
Поскольку речь идет о языке "C" - то надо корректно обрабатывать ошибки open/read/write/fseek/close и реагировать на них. И закрывать файловые хендлы при любом возможном исходе. Ну и не забывать делать free() после malloc(). Грубо говоря количество malloc должно быть всегда равно free.
Если была смерть posix-потока то надо как-то найти все брошеные дескрипторы-сироты и закрыть их тоже. Тоесть процесс-родитель должен как-то их видеть.
Можно эту прямоугольную "колбасу" вообще не поворачивать. А хранить вектор повернутости. И перегрузить оператор индекса чтобы доступ вел себя по правилам аффинных преобразований.