Вы не записывали свои данные там, где, как вы думали, были, потому что вы неправильно обращались к tt
. Ваш неверный доступ был непротиворечивым, и, следовательно, вы могли прочитать первую запись, но вторая запись была далеко не там, где вы думали, что она была фактически записана в неинициализированную память и никогда не сохранялась. Попытка доступа к загруженным данным показывает это. Кроме того, ИНТ * в вашей структуре не мог быть написано правильно, как вы написали это, но это спорный вопрос, потому что, как ваша программа структурированной было бы неправильно, если вы пытаетесь загрузить файл в отдельном счете программы. fwrite
и fread
не могут следовать за вашим int*
, потому что он только смотрит на вашу структуру как битовый паттерн - он точно восстанавливает ваш указатель, но теперь у вас есть указатель на случайный кусок памяти, который вы не сделали на самом деле делать что-нибудь с! В этом случае, однако, ваши указатели остаются действительными, потому что вы никогда не перезаписывали данные, но это характерно для сценария записи файла, без очистки памяти и чтения его обратно без закрытия программы, что не является реалистичный сценарий для написания файлов. Есть еще один вопрос StackOverflow, который более подробно объясняет эту ошибку.
Во всяком случае, здесь есть гораздо большая проблема с тем, как вы обращаетесь к памяти, с удалением других строк:
dd (*tt)[5];
//...
tt=malloc(sizeof(struct ss[5]));
for(i=0;i<5;i++){
tt[i]->p=malloc(sizeof(int));
tt[i]->p=&a[i];
//...
}
Объявления C читаются с помощью Правило спирали по часовой стрелке , поэтому давайте посмотрим, что мы сказали о tt
, и сравним его с тем, как мы его используем.
tt
- имя переменной. Справа от него закрывающая скобка, поэтому мы продолжаем обрабатывать текущую область. Мы встречаем *
, а затем совпадающее слово, затем статический размер массива, а затем тип. Используя Правило спирали по часовой стрелке, tt
является указателем на массив (размер 5) с dd
. Это означает, что если вы разыменовываете tt (используя (*tt)
), вы получаете dd[5]
, или, если вы предпочитаете думать об этом таким образом (безусловно, так делает C), указатель на начало блока памяти, достаточно большой держать вашу структуру. Что еще более важно, это то, что вы сказали, что это. C на самом деле не очень требователен к типам указателей, и именно поэтому ваш код компилируется, даже если вы совершаете серьезную ошибку типа.
Ваш оператор malloc верен: он инициализирует tt
с областью памяти, которая, как обещала операционная система, имеет достаточно места для ваших пяти ss
. Поскольку C не занимается глупыми вещами, такими как проверка границ размера массива, 5-элементный массив, равный struct ss
, гарантированно будет в пять раз больше размера одного struct ss
, так что вы могли бы написать malloc(5 * sizeof(dd))
, но в любом случае это нормально.
Но давайте посмотрим, что здесь происходит:
tt[i]->p=malloc(sizeof(int));
Ой-ой. tt
- это указатель на массив структуры dd
, но вы только что обработали его как массив указателей на структуру dd
.
Что вы хотели:
- Разыменование
tt
- Найдите
i
-й элемент в массиве указателей на dd
- Перейти к полю
p
- Назначьте ему указатель на пробел для int
Что вы на самом деле получили:
- Найдите
i
-й элемент в массиве указателей на массивы dd
- Разыменяем его, трактуя его как указатель на
dd
, поскольку C не знает разницы между массивами и указателями
- Перейти косвенно к полю
p
- Назначьте ему указатель на пробел для int
Когда i
равно 0, это работает правильно, потому что нулевой элемент в массиве и сам массив находятся в одном месте. (Массив не имеет заголовка, и C _ не понимает разницы между массивами и указателями и позволяет использовать их взаимозаменяемо, поэтому он компилируется вообще.)
Когда i
не равно 0, вы запутываете память.Теперь вы пишете в любую память, которая следовала вашему указателю!Это на самом деле указатель, но вы сказали C, что это массив, и он поверил вам, добавил 1 элемент ширины к своему местоположению и попытался выполнить все эти операции.Вы используете массивы именно там, где вы должны использовать указатели, и указатели точно там, где вы должны использовать массивы.
Вы записываете только в память, выделенную для элемента 0. Помимо этого, вы пишете в несвязанныепамять, и это удача (неудача, в вашем случае), которая предотвратила крах вашей программы.(Если бы это было так, вам было бы легче найти это как строку виновности.) Когда вы fwrite
используете выделенную память, первый элемент действителен, остальное - мусор, а ваши fread
приводят к даннымструктура, которая имеет один действительный элемент, затем случайный мусор кучи, который привел к падению, когда вы попытались разыменовать указатель (это было бы допустимо только потому, что программа не завершилась).
Вот правильный способ доступаваш указатель на массив:
(*tt)[i].p=malloc(sizeof(int));
...
Кроме того, вы выделяете память, а затем сразу же забываете свою единственную ссылку на нее, которая является утечкой памяти, так как выперезаписываем указатель ссылкой на статический массив, с которым вы все инициализируете.Используйте это вместо:
*((*tt)[i].p)=a[i]
Я настоятельно рекомендую вам изучить Учебник по указателям и массивам в полном объеме.Это поможет вам избежать этой проблемы в будущем.
Имейте в виду, что вы читаете xx
неправильно при печати его содержимого точно таким же образом.