Ваш пример "обновления" завершен? Я не думаю, что это скомпилируется: оно требует возвращаемого значения, но вы никогда ничего не возвращаете. Вы никогда ничего не будете делать полным ходом, но, возможно, это преднамеренно, может быть, ваша точка зрения состоит в том, чтобы просто сказать, что когда вы делаете malloc, другие вещи ломаются.
Не видя звонящего, невозможно однозначно сказать, что здесь происходит. Я предполагаю, что paths - это динамически распределенный блок, который был свободен до того, как вы вызвали эту функцию. В зависимости от реализации компилятора может показаться, что блок free'd может содержать действительные данные до тех пор, пока будущий malloc не займет место.
Обновление: чтобы ответить на вопрос
Обработка строк - хорошо известная проблема в C. Если вы создаете массив фиксированного размера для хранения строки, вам нужно беспокоиться о длинной строке, переполняющей выделенное пространство. Это означает постоянную проверку размеров строк на копиях с использованием strncpy и strncat вместо простых strcpy и strcat или аналогичных методов. Вы можете пропустить это и просто сказать: «Ну, ни у кого никогда не будет имени длиннее 60 символов» или чего-то подобного, но всегда есть опасность, что кто-то это сделает. Даже для чего-то, что должно иметь известный размер, например, номер социального страхования или номер ISBN, кто-то может ошибиться, введя его и дважды нажав клавишу, или злонамеренный пользователь может намеренно ввести что-то длинное. И т.д. Конечно, это в основном проблема с вводом данных или чтением файлов. Если у вас есть строка в поле некоторого известного размера, то для любых копий или других манипуляций вы знаете размер.
Альтернативой является использование динамически размещаемых буферов, где вы можете сделать их настолько большими, насколько это необходимо. Это звучит как хорошее решение, когда вы впервые слышите это, но на практике это гигантская боль в C, потому что выделение буферов и их освобождение, когда они вам больше не нужны, - большая проблема. Другой автор здесь сказал, что функция, которая выделяет буфер, должна быть той же самой, что освобождает его. Я согласен с хорошим практическим правилом, но ... Что если подпрограмма хочет вернуть строку? Таким образом, он выделяет буфер, возвращает его и ... как он может его освободить? Это не может быть, потому что все дело в том, что он хочет вернуть его вызывающей стороне. Вызывающий не может выделить буфер, потому что он не знает размер. Также, казалось бы, простые вещи вроде:
if (strcmp(getMeSomeString(),stringIWantToCompareItTo)==0) etc
невозможно. Если функция getMeSomeString выделяет строку, конечно, она может вернуть ее, поэтому мы проводим сравнение, но теперь мы потеряли дескриптор и никогда не сможем его освободить. В итоге вам приходится писать неловкий код, такой как
char* someString=getMeSomeString();
int f=strcmp(someString,stringIWantToCompareItTo);
free(someString);
if (f==0)
etc
Итак, все работает, но читабельность просто упала.
На практике я обнаружил, что, когда разумно ожидать, что строки имеют приемлемый размер, я выделяю буферы фиксированной длины. Если вход больше буфера, я либо усекаю его, либо выдаю сообщение об ошибке, в зависимости от контекста. Я использую динамически распределенные буферы, только когда размер потенциально велик и непредсказуем.