C — fread, похоже, не считывает данные обратно в память

#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» для печати, он по-прежнему печатает пустой список деталей