#c #structure #binaryfiles #fread
#c #структура #двоичные файлы #fread
Вопрос:
У меня проблема, и я не уверен, что ее вызывает, потому что эта книга, которую я читаю, на самом деле не объясняет функцию fread досконально, и даже после прочтения некоторых сообщений здесь я все еще не могу понять, что происходит. Я полагаю, это как-то связано с чтением структуры обратно в память
Проблема в том, что когда он восстанавливает массив, он по-прежнему выводит пустой, как если бы он не был восстановлен, но утверждает, что все 100 частей были восстановлены. Я сделал только 3 части структуры, когда я ее сбросил, может ли это быть проблемой?
Структура имеет такую форму
#define MAX_PARTS 100
struct part {
int number;
char name[NAME_LEN 1];
int on_hand;
} inventory[MAX_PARTS];
И вот функции
void dump(void)
{
FILE *fp;
const char *inv = "inventory.dat";
int chk;
if ((fp = fopen(inv, "wb")) == NULL) {
fprintf(stderr, "Can't open file "%s"n", *inv);
exit(EXIT_FAILURE);
}
chk = fwrite(inventory, sizeof(struct part), MAX_PARTS, fp);
if (feof(fp)) {
fprintf(stderr, "End of file reachedn");
} else if (ferror(fp)) {
fprintf(stderr, "A write error occuredn");
}
fclose(fp);
printf("File has Dumped %d of %dn", chk, num_parts);
}
void restore(void)
{
FILE *fp;
const char *inv = "inventory.dat";
int chk;
if ((fp = fopen(inv, "rb")) == NULL) {
fprintf(stderr, "Can't open file "%s"n", *inv);
exit(EXIT_FAILURE);
}
chk = fread(inventory, sizeof(struct part), MAX_PARTS, fp);
if (feof(fp)) {
fprintf(stderr, "End of file reachedn");
} else if (ferror(fp)) {
fprintf(stderr, "A read error occurredn");
}
fclose(fp);
printf("File has restored %d partsn", chk);
}
Остальная часть кода:
/* Maintains a parts database (array version) */
#include <stdio.h>
#include <stdlib.h>
#include "readline.h"
#define NAME_LEN 25
#define MAX_PARTS 100
struct part {
int number;
char name[NAME_LEN 1];
int on_hand;
} inventory[MAX_PARTS];
int num_parts = 0; /* number of parts currently stored */
void dump(void);
void restore(void);
int find_part(int number);
void insert(void);
void search(void);
void update(void);
void print(void);
/**********************************************************
* main: Prompts the user to enter an operation code, *
* then calls a function to perform the requested *
* action. Repeats until the user enters the *
* command 'q'. Prints an error message if the user *
* enters an illegal code. *
**********************************************************/
int main(void)
{
char code;
for (;;) {
printf("Enter operation code: ");
scanf(" %c", amp;code);
while (getchar() != 'n') /* skips to end of file */
;
switch (code) {
case 'd': dump();
break;
case 'r': restore();
break;
case 'i': insert();
break;
case 's': search();
break;
case 'u': update();
break;
case 'p': print();
break;
case 'q': return 0;
default: printf("Illegal coden");
}
printf("n");
}
}
void dump(void)
{
FILE *fp;
const char *inv = "inventory.dat";
int chk;
if ((fp = fopen(inv, "wb")) == NULL) {
fprintf(stderr, "Can't open file "%s"n", *inv);
exit(EXIT_FAILURE);
}
chk = fwrite(inventory, sizeof(struct part), MAX_PARTS, fp);
if (feof(fp)) {
fprintf(stderr, "End of file reachedn");
} else if (ferror(fp)) {
fprintf(stderr, "A write error occuredn");
}
fclose(fp);
printf("File has Dumped %d of %dn", chk, num_parts);
}
void restore(void)
{
FILE *fp;
const char *inv = "inventory.dat";
int chk;
if ((fp = fopen(inv, "rb")) == NULL) {
fprintf(stderr, "Can't open file "%s"n", *inv);
exit(EXIT_FAILURE);
}
chk = fread(inventory, sizeof(struct part), MAX_PARTS, fp);
if (feof(fp)) {
fprintf(stderr, "End of file reachedn");
} else if (ferror(fp)) {
fprintf(stderr, "A read error occurredn");
}
fclose(fp);
printf("File has restored %d partsn", chk);
}
/**********************************************************
* find_part: Looks up a part number in the inventory *
* array. Returns the array index if the part *
* number is found, otherwise, returns -1. *
**********************************************************/
int find_part(int number)
{
int i;
for (i = 0; i < num_parts; i )
if (inventory[i].number == number)
return i;
return -1;
}
/**********************************************************
* insert: Prompts the user for information about a new *
* part and then inserts the part into the *
* database. Prints an error message and returns *
* prematurely if the part already exists or the *
* database is full. *
**********************************************************/
void insert(void)
{
int part_number;
if (num_parts == MAX_PARTS) {
printf("Database is full; can't add more parts.n");
return;
}
printf("Enter part number: ");
scanf("%d", amp;part_number);
if (find_part(part_number) >= 0) {
printf("Part already exists.n");
return;
}
inventory[num_parts].number = part_number;
printf("Enter part name: ");
read_line(inventory[num_parts].name, NAME_LEN);
printf("Enter quantity on hand: ");
scanf("%d", amp;inventory[num_parts].on_hand);
num_parts ;
}
/**********************************************************
* search: Prompts the user to enter a part number, then *
* looks up the part in the database. If the part *
* exists, prints the name and quantity on hand; *
* if not, prints an error message. *
**********************************************************/
void search(void)
{
int i, number;
printf("Enter part number: ");
scanf("%d", amp;number);
i = find_part(number);
if (i >= 0) {
printf("Part name: %sn", inventory[i].name);
printf("Quantity on hand: %dn", inventory[i].on_hand);
} else
printf("Part not found.n");
}
/**********************************************************
* update: Prompts the user to enter a part number. *
* Prints an error message if the part doesn't *
* exist; otherwise, prompts the user to enter *
* change in quantity on hand and updates the *
* database. *
**********************************************************/
void update(void)
{
int i, number, change;
printf("Enter part number: ");
scanf("%d", amp;number);
i = find_part(number);
if (i >= 0) {
printf("Enter change in quantity on hand: ");
scanf("%d", amp;change);
inventory[i].on_hand = change;
} else
printf("Part not found.n");
}
/**********************************************************
* print: Prints a listing of all parts in the database, *
* showing the part number, part name, and *
* quantity on hand. Parts are printed in the *
* order in which they were entered into the *
* database. *
**********************************************************/
void print(void)
{
int i;
printf("Part Number Part Name "
"Quantity on Handn");
for (i = 0; i < num_parts; i )
printf("} %-25sdn", inventory[i].number,
inventory[i].name, inventory[i].on_hand);
}
Комментарии:
1. Вы не вставили достаточно кода, чтобы мы могли воспроизвести проблему. Вероятно, ошибка в коде не показана.
2. @DavidSchwartz Я добавил остальную часть кода … Не уверен, как это поможет, но спасибо за помощь
3. Это помогает, потому что именно там была ошибка. Смотрите мой ответ.
4. Спасибо @DavidSchwartz Я полный идиот
5. Действительно легко застрять в деталях и пропустить что-то абсурдно очевидное, как только кто-то укажет вам на это. Часто помогает сделать перерыв в коде, а затем вернуться к нему заново. Но определенно приобретите привычку добавлять
printf
в код множество операторов, чтобы сузить проблему. (Или научитесь использовать хороший отладчик.)
Ответ №1:
Самые простые попытки отладки выявили бы ошибку. Простое добавление ведения журнала в print
функцию сделало бы проблему очевидной.
При восстановлении вы не меняетесь num_parts
. Поэтому, когда вы просите его распечатать, он печатает нулевые части. Если num_parts
это часть данных, необходимых вашей программе, то их тоже необходимо сохранить / восстановить. В качестве альтернативы, запишите только количество заполненных частей и установите num_parts
в вашей функции восстановления количество прочитанных частей.
Комментарии:
1. LOL хахаха, я чувствую себя полным идиотом, извините, что даже беспокоил вас, ребята, по этому поводу… Мне просто показалось, что эта книга быстро прочитала и записала в файлы, и поэтому я подумал, что каким-то образом упускаю из виду что-то, связанное с fwrite или fread .
Ответ №2:
Как вы написали MAX_PARTS
, он прочитает эти многие записи. Так chk
и будет MAX_PARTS
.
Это даст вам все, что вы написали. Если вы написали допустимые 3 записи, тогда он должен прочитать 3 допустимых записи, остальные будут мусором.
Комментарии:
1. Хорошо, я внес это изменение, теперь он записывает только количество сохраненных в данный момент деталей и восстанавливает то же количество деталей …. но когда я выбираю «p» для печати, он по-прежнему печатает пустой список деталей