【问题标题】:Unexpected behaviour of fread() reading from binary filefread() 从二进制文件读取的意外行为
【发布时间】:2016-04-19 14:36:48
【问题描述】:

这个程序基本上创建了一个包含所有信息的航班列表(由 ListaVoli.bin 中的 fread() 函数读取)。 该列表主要由节点组成,每个节点包含一个航班。

#include <stdio.h>
#include <stdlib.h>

#define FILE_NAME "/Users/Matt/Downloads/ListaVoli.bin"

struct flight {
    int flightCode;
    char destination[3];
    int scheduledDepHour;
    int scheduledDepMinute;
    int realDepHour;
    int realDepMinute;
    int passengers;
};

struct node {
    struct flight volo;
    struct node *next;
};

struct node *addToList(struct node *list, struct flight voloIn) {
    struct node *newNode;
    newNode = malloc(sizeof(struct node));

    if (newNode == NULL) {
        printf("Error: malloc failed\n");
        exit(EXIT_FAILURE);
    }

    newNode -> volo = voloIn;
    newNode -> next = list;
    return newNode;
}

void printList(struct node *list) {
    for (; list != NULL; list = list -> next) {
        printf("Code:%d\nDestination:%s\nDeparture:%d-%d\nReal:%d-%d\nPassengers:%d\n\n\n",
        list -> volo.flightCode,
        list -> volo.destination,
        list -> volo.scheduledDepHour,
        list -> volo.scheduledDepMinute,
        list -> volo.realDepHour,
        list -> volo.realDepMinute,
        list -> volo.passengers
        );
    }
}

void decolla(struct node *list, int flightCode, int realDepHour, int realDepMinute) {
    for (; list != NULL; list = list -> next) {
        if (flightCode == (list -> volo.flightCode)) { /*
            printf("Inserisci ora di partenza per il volo %d: ", flightCode);
            scanf("%d", &(list -> volo.realDepHour));
            printf("Inserisci minuto di partenza: ");
            scanf("%d", &(list -> volo.realDepMinute)); */
            list -> volo.realDepHour = realDepHour;
            list -> volo.realDepMinute = realDepMinute;
        }
    }
}

void delay(struct node *list) {
    for (; list != NULL; list = list -> next) {
        if ((list -> volo.realDepHour) - (list -> volo.scheduledDepHour) == 0) {
            if ((list -> volo.realDepMinute) - (list -> volo.scheduledDepMinute) > 5 && (list -> volo.realDepMinute) - (list -> volo.scheduledDepMinute) < 30) {
            printf("Il volo %d ha più di 5 minuti di ritardo\n", list -> volo.flightCode);
            continue;
            }
            if ((list -> volo.realDepMinute) - (list -> volo.scheduledDepMinute) > 30) {
                printf("Il volo %d ha più di 30 minuti di ritardo\n", list -> volo.flightCode);
                continue;
            }
        } else
            printf("Il volo %d ha più di 30 minuti di ritardo\n", list -> volo.flightCode);
    }
}

void passengersCount(struct node *list) {
    for (; list != NULL; list = list -> next) {
        if (list -> volo.passengers > 200) {
            printf("Il volo %d ha più di 200 passeggeri\n", list -> volo.flightCode);
            continue;
        }
    }
}

int main() {
    FILE *fp;
    struct node *first = NULL;
    struct flight volo;

    /* Apro il file e controllo che sia stato aperto correttamente */
    if ((fp = fopen(FILE_NAME, "rb")) == NULL) {
        printf("Can't open %s\n", FILE_NAME);
        exit(EXIT_FAILURE);
    }

    for (int i = 0; i < 4; i++) {
        fread(&volo, sizeof(int), 7, fp);
        first = addToList(first, volo);
    }

    decolla(first, 3497, 11, 30);
    decolla(first, 2193, 11, 53);
    decolla(first, 4284, 11, 07);
    decolla(first, 5536, 12, 26);
    printList(first);
    delay(first);
    passengersCount(first);

    /* Controllo che il file sia chiuso correttamente */
    if (fclose(fp) == EOF) {
        printf("File not closed properly!");
        exit(EXIT_FAILURE);
    }
    return 0;
}

代码编译正确,所以不用担心整个代码,专注于 main() 函数和两个结构。 关于 main() 函数中的 fread() 函数,我有两个问题:

  1. 为什么,如果我把 sizeof(int) 作为第二个参数,flight.destination 的值是正确分配的? char[3] 变量不应该大于 sizeof(int) 吗?
  2. 为什么,如果我将 sizeof(struct flight) 作为第二个参数(这将是最佳选择),我会得到分段错误:11?

【问题讨论】:

  • 如果其余代码无关紧要,您不应该发布它。这就是minimal reproducible example第一部分的想法。
  • 您需要代码才能更好地理解程序。刚才说了,问题不在于整个程序,而在于main()函数中的fread()函数。
  • 没关系,但是从二进制文件中读取是复杂的,一个位就会产生大问题。正如你所说, int 是 4 个字节, char[3] 是 3 个字节,那么 fread() 应该读取的字节数比它应该的多吗?那为什么我得到正确的输出(3个字符的字符串)?
  • 不需要“懂程序”。您必须说明您的具体问题是什么,并提供必要代码来重现。 SO 是一个问答网站,而不是论坛。见How to Ask

标签: c data-structures struct linked-list fread


【解决方案1】:

三个字符的数组是三个字节。 int 通常是(至少在现代 32 位和 64 位平台上)4 个字节。它可以读取sizeof(int),因为编译器添加了 padding

但读取结构的“正确”(或至少通常的)方法是将整个结构作为一个单元读取,即在您的情况下使用sizeof(volo)

fread(&volo, sizeof(volo), 1, fp);

如果您因此而出现其他错误,则说明您做错了else

【讨论】:

  • 实际上更好(和正确)的方法是正确(de)按元素序列化它。
  • 为什么你写 1 作为第三个参数而不是我写的 7?我的解决方案不正确吗?
  • 似乎是 7 导致了分段错误:11 错误
  • @matt95 第二个参数是要读取的每个元素的size,第三个参数是要读取的元素的number个。跨度>
  • @matt95 是的,您显示的代码将读取七个int 元素。
猜你喜欢
  • 1970-01-01
  • 2015-08-22
  • 2019-04-13
  • 1970-01-01
  • 2020-06-09
  • 1970-01-01
  • 1970-01-01
  • 2019-12-03
  • 2014-06-10
相关资源
最近更新 更多