Это предварено моими главными комментариями.
Теперь, когда достаточно кода было отправлено ...
Ключевая проблема заключается в том, что в main
, scale
- это цикл в области (т. Е. не выделена куча)
Таким образом, даже если fgetLine
возвращает malloc
ed буфер и результаты strtok
точки вызова в пределах этого буфера, адрес scale
, переданный List_prepend
, будет один и тот же адрес на каждой итерации в main
.
List_prepend
делает не malloc
и memcpy
свой аргумент data
(и не знает, какую длину ему нужно будет использовать), поэтому абонент из List_prepend
должен сделать это.
Таким образом, мы должны исправить это в main
, изменив:
for (char *line; (line = fgetLine(fp));) {
struct scale_t scale;
scale.name = strtok(line, ",\t");
scale.intervals = strtok(NULL, ",\040\t");
List_prepend(head, &scale);
}
В
for (char *line; (line = fgetLine(fp));) {
struct scale_t *scale = malloc(sizeof(struct scale_t));
scale->name = strtok(line, ",\t");
scale->intervals = strtok(NULL, ",\040\t");
List_prepend(head, scale);
}
UPDATE:
есть ли название для явления, в котором «адрес масштаба, передаваемый в List_prepend, будет тем же адресом на каждой итерации в main.»? Я думал, что нахождение в цикле будет означать, что каждый раз будет создаваться новый масштаб, и я мог бы перенести эти временные значения в List_prepend.
Переменные области видимости цикла и области действия попадают в кадр стека функций. Возможно, будет проще понять, почему не работает , если вы переместили struct scale_t scale;
в область действия функции.
Loop scope может сделать небольшой обман с указателем стека [или может не ]. Он может просто скомпилировать код, как если бы определение было функциональной областью.
Или это может быть сделано:
В верхней части цикла указатель стека уменьшается на sizeof(struct stack_t)
[с соответствующим выравниванием].
Затем scale
получает этот адрес. Это передается List_prepend
.
В нижней части цикла scale
выйдет из области видимости, поэтому указатель стека увеличивается на sizeof(struct stack_t)
.
Теперь указатель стека снова имеет свое первоначальное значение. Тот, который был в верхней части предыдущей итерации цикла.
пена, промыть, повторить ...
Оптимизирующий компилятор может увидеть, что выполнение последовательности декремента / приращения внутри цикла бесполезно. Он может переместить декремент выше цикла и приращение после цикла, достигая того же эффекта.