Привет, ребята! Помогите, пожалуйста, считать структуры из файла, выделяя блок динамической памяти для хранения прочитанных данных. Буду очень признателен)
int load (struct zvezda *p, int max)
{
FILE *file;
char fname[20];
int i;
printf("Укажите имя файла и путь к нему: ");
scanf ("%s", fname);
file=fopen(fname, "rb");
if (file == NULL)
{
printf("Возникла ошибка!");
return(0);
}
max = fread(p, sizeof(*p), max, file);
fclose(file);
return max;
}
Ребята, пожалуйста, помогите использовать динамическую память при создании массива данных в case 1!
int main()
{
struct zvezda A[50];
int number, n=0, i, k, d=0;
double zv;
system("chcp 1251 > nul");
while (d<2) {
system("cls");
printf("___________________________________________________________________\n"
"********************|-----------MENU----------|********************\n"
"*******************************************************************\n"
"* 1. Добавить запись *\n"
"* 2. Вставить запись *\n"
"* 3. Удалить запись *\n"
"* 4. Просмотреть запись *\n"
"* 41 - по указанному номеру *\n"
"* 42 - по видимой величине *\n"
"* 43 - все записи *\n"
"* 5. Сортировать записи (по возрастанию расстояния до Земли) *\n"
"* 6. Сохранить записи в файл *\n"
"* 7. Загрузить записи из файла *\n"
"* ??? *\n"
"* 9. Выйти из меню *\n"
"*******************************************************************\n>> ");
fflush(stdin);
scanf("%d", &number);
switch (number) {
case 1:
if (n < 50)
{
printf("Запись №%d:\n", n+1);
vvod(&A[n]);
n++;
}
else
printf("\aНет памяти!\n");
system("pause");
break;
Например, при сохранении записать в начало файла количество записанных объектов.
Потом при чтении читать это количество, выделять нужный размер памяти через malloc, ну и дальше можно fread как в первом сообщении.
Не… Пока интересует только по данному отрывку добавление элемента. Помоги, пожалуйста, эту строчку правильно составить.
int main()
{
struct zvezda * A;
int number, n=0, i, k, d=0;
double zv;
system("chcp 1251 > nul");
while (d<2) {
system("cls");
printf("___________________________________________________________________\n"
"********************|-----------MENU----------|********************\n"
"*******************************************************************\n"
"* 1. Добавить запись *\n"
"* 2. Вставить запись *\n"
"* 3. Удалить запись *\n"
"* 4. Просмотреть запись *\n"
"* 41 - по указанному номеру *\n"
"* 42 - по видимой величине *\n"
"* 43 - все записи *\n"
"* 5. Сортировать записи (по возрастанию расстояния до Земли) *\n"
"* 6. Сохранить записи в файл *\n"
"* 7. Загрузить записи из файла *\n"
"* ??? *\n"
"* 9. Выйти из меню *\n"
"*******************************************************************\n>> ");
fflush(stdin);
scanf("%d", &number);
switch (number) {
case 1:
A = (struct zvezda *)malloc(sizeof(struct zvezda) * n) //или вообще не так?
printf("Запись №%d:\n", n+1);
vvod(&A[n]);
n++;
}
break;
malloc в самом начале нужен.
Потом, когда не хватает памяти, надо перевыделять (выделять новую память большего размера, копировать туда). В С вроде realloc это делает: https://en.cppreference.com/w/c/memory/realloc
В идеале создать абстракцию “Динамический Массив”, по примеру std::vector из С++.
То есть например структура DynamicArray с полями размер и сам обычный массив (указатель), и работать с ней через функции типа append, insert, remove, которые проверяют размер и перевыделяют когда нужно.
И еще для оптимизации производительности обычно размер памяти увеличивают например в 2 раза, а не +1 элемент (хранят отдельно реальный размер и используемый размер).
Похоже на правду?) В case 1 элемент добавляется, в case 2 - вставляется
case 1:
if (A == NULL)
{
A = (struct zvezda*)malloc(sizeof(struct zvezda) * (n+1)); /* создаем массив динамически */
if (!A) /* проверка, удалось ли выделить память */
{
printf("Ошибка при выделении памяти!!\n");
system("pause");
return 1;
}
}
else
{
A = (struct zvezda*)realloc(A, sizeof(struct zvezda) * (n+1));
if (!A) /* проверка, удалось ли выделить память */
{
printf("Ошибка при выделении памяти!!\n");
system("pause");
return 1;
}
}
printf("Запись №%d:\n", n+1);
vvod(&A[n]);
n++;
break;
case 2:
k = dobav_number(n) - 1;
if (k==-1)
{
printf("Записи отсутствуют!\n");
system("pause");
break;
}
if (A == NULL)
{
A = (struct zvezda*)malloc(sizeof(struct zvezda) * (n+(k+1))); /* создаем массив динамически */
if (!A) /* проверка, удалось ли выделить память */
{
printf("Ошибка при выделении памяти!!\n");
system("pause");
return 1;
}
}
else
{
A = (struct zvezda*)realloc(A, sizeof(struct zvezda) * (n+(k+1)));
if (!A) /* проверка, удалось ли выделить память */
{
printf("Ошибка при выделении памяти!!\n");
system("pause");
return 1;
}
}
if (k >= 0)
{
for (i = n-1; i >= k; i--)
{
A[i+1] = A[i];
}
printf("\nВведите информацию для записи №%d:\n\n", k+1);
vvod(&A[k]);
}
n++;
break;
Так вот чтобы не копипастить if NULL, malloc и т.д. во все case и нужна абстракция как в примере выше )
Тогда бы всё было в 100500 раз проще:
create(&stars);
switch ...
case 1:
star = inputStarData();
append(&stars, star);
break;
case 2:
k = ...;
star = inputStarData();
insert(&stars, k, star);
break;
Что-то странное
Размер же всегда просто +1, причем тут k.
В предыдущем коде A кстати не инициализировано и не факт, что NULL.
Это примерно одно и то же, лучше выбрать какой-то один из этих вариантов )
Alex P., подскажи, пожалуйста, что я не так здесь делаю?
int load (struct zvezda *p)
{
FILE *file;
char fname[20];
int i;
printf("Укажите имя файла и путь к нему: ");
scanf ("%s", fname);
file=fopen(fname, "rb");
if (file == NULL)
{
printf("Возникла ошибка!");
return(0);
}
// определяем размер файла
fseek(file , 0 , SEEK_END); // устанавливаем позицию в конец файла
long lSize = ftell(file); // получаем размер в байтах
rewind (file); // устанавливаем указатель в конец файла
p = (struct zvezda* )malloc(sizeof(*p) * lSize); // выделить память для хранения содержимого файла
if (p == NULL)
{
printf("Возникла ошибка!");
return 0;
}
size_t result = fread(p, sizeof(*p), lSize, file);
if (result != lSize)
{
printf("Возникла ошибка!");
return 0;
}
fclose(file);
return result;
}
int load (struct zvezda *p)
{
FILE *file;
char fname[20];
int i;
printf("Укажите имя файла и путь к нему: ");
scanf ("%s", fname);
file=fopen(fname, "rb");
if (file == NULL)
{
printf("Возникла ошибка 1!");
return(0);
}
// определяем размер файла
fseek(file , 0 , SEEK_END); // устанавливаем позицию в конец файла
long lSize = ftell(file); // получаем размер в байтах
rewind (file); // устанавливаем указатель в конец файла
p = (struct zvezda* )malloc(sizeof(*p)); // выделить память для хранения содержимого файла
if (p == NULL)
{
printf("Возникла ошибка 2!");
return 0;
}
size_t result = fread(p, sizeof(*p), lSize, file);
if (result != lSize)
{
printf("Возникла ошибка 3!");
return 0;
}
fclose(file);
return result;
}
Ребята, привет! Помогите, пожалуйста исправить вот эти ошибки в приведенной ниже функции:
у схемы *A=realloc(*A, …); есть серьезный недостаток: если память перевыделить не удалось, то обнуляется рабочий указатель и мы теряем наш массив, хотя в случае ошибки старый блок не уничтожается и данные в нем актуальны. В таких ситуациях надо использовать вспомогательный указатель, проверять его, а потом присваивать рабочему, если все в порядке.
кстати, если указатель на блок нулевой, то realloc ведет себя как malloc, т.е. просто выделяет память, это может упростить реализацию.
освободив блок, надо обнулить и указатель на него.
в штатных ситуациях функция завершается, не возвращая значение явно. Результат непредсказуем. Как снаружи узнать, удалось выполнить операцию с памятью или нет?
Заранее спасибо!
int memory(struct zvezda ** A, int n, int q)
{
if (q == 1)
{
if (*A == NULL)
{
*A = (struct zvezda* )malloc(sizeof(struct zvezda) * (n+1));
if (*A == NULL) /* проверка, удалось ли выделить память */
{
printf("Ошибка при выделении памяти!\n");
system("pause");
return 0;
}
}
else
{
*A = (struct zvezda* )realloc(*A, sizeof(struct zvezda) * (n+1));
if (*A == NULL) /* проверка, удалось ли выделить память */
{
printf("Ошибка при выделении памяти!\n");
system("pause");
return 0;
}
}
}
if (q == 2)
{
*A =(struct zvezda* )realloc(*A, sizeof(struct zvezda) * n );
if (*A == NULL) /* проверка, удалось ли выделить память */
{
return 0;
}
}
if (q == 3)
{
free (*A);
}
}
Да, тут почему-то не во всех случаях завершения функции есть return.
И непонятно что она возвращает (что такое 0?). Если “не успешно”/“успешно” (0/не ноль), то с C99 есть bool: https://en.wikibooks.org/wiki/C_Programming/stdbool.h
Значит можно убрать q и все if (кроме проверки для первого замечания тут). И передавать сразу в параметр n или n+1.
q == 3 непонятно для чего нужен. Это ж просто один вызов в конце программы и free(A) намного проще понять, чем memory(A, n, 3);