【问题标题】:C load from file to struct specificatorsC从文件加载到结构说明符
【发布时间】:2021-01-17 14:24:54
【问题描述】:

我正在尝试从文件加载到结构中的特定字段。我对规范有很大的问题。我应该逐个加载符号还是只加载整个字符串?任何人都可以帮助我的规范吗?结构值包含位:5、5 和 11,它应该是这样的。我应该忽略第一个数字1. , 2. , 3.

编辑。如果是二进制文件呢?

输入文件:

1. John Snow, 05/06/1996 (0x00000000001f3cc1)⏎
2. Ethan Downey Jr., 14/02/1945 (0x00000000001e644e)⏎
...
10. ...
union unione{
    unsigned long value;
    struct {
        unsigned char d : 5;
        unsigned char m : 5;
        unsigned short int y : 11;
    }bit;
};

struct structure {
    char name[21];
    union unione bity;
    char surname[31];
};

int readfile(const char* filename, struct structure* buffer, int size){
    if (!fname || !buffer || size < 1) return 1;

    FILE *f = fopen(filename, "r");
    if(!f) return 2;

    for(int i = 0; i < 10; i++) {
        fscanf(f, "%*d. %s %s, %d/%d/%d (%x)", (*(buffer+i)).name, (*(buffer+i)).surname, (*(buffer+i)).bity.bit.d,
               (*(buffer+i)).bity.bit.m, (*(buffer+i)).bity.bit.y, (*(buffer+i)).bity.value);
    }
}

int main() {
    struct structure data[10];
    readfile("birthdays.bin", data, 10);
}

【问题讨论】:

    标签: c file struct


    【解决方案1】:

    我认为这种方法存在更多问题。

    第一个问题是文件和 fscanf:fscanf 以预定义的格式读取,但是您的名称包含 2 部分和包含 3 部分的名称,例如“John Snow”和“Ethan Downey Jr.”。这读起来很麻烦,我建议你只使用 2 部分名称,并在算作 1 的部分之间放置一些特殊字符,以便以后将它们分开。就像这个“Ethan Downey_Jr.”。您将名称读取为两个字符串,然后将 '_' 替换为 ' '。

    我不清楚的另一件事是工会。它有一个“值”和包含日、月和年的结构。现在,union 占据了它最大成员的内存位置,这意味着这些字段、值和结构都占用了相同的内存(long 较大)。因此,将日、月和年重新加入并用值覆盖它们并没有真正意义。如果“日、月、年”结构和“值”具有相同的值,那么它在文本文件中是冗余的,这也是不优选的。

    所以我的建议:想想这个槽,“value”和“struct bit”是一样的吗?也许使用结构而不是联合?如果它们相同,那么文本文件中有冗余,你需要吗?

    但无论如何,一种解决方案是:

    #ifdef _MSC_VER
    #define _CRT_SECURE_NO_WARNINGS
    #endif
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    union unione {
        unsigned long value;
        struct {
            unsigned char d : 5;
            unsigned char m : 5;
            unsigned short int y : 11;
        }bit;
    };
    
    struct structure {
        char name[21];
        union unione bity;
        char surname[31];
    };
    
    int readfile(const char* filename, struct structure* buffer, int size) {
        if (!filename || !buffer || size < 1) return 1;
    
        FILE *f = fopen(filename, "r");
        if (!f) return 2;
    
        for (int i = 0; i < size; i++) {
            int day, month, year, value;
            memset(buffer[i].name, 0, 21);
            memset(buffer[i].surname, 0, 31);
            buffer[i].bity.value = 0;
            fscanf(f, "%*d. %s %[^,], %d/%d/%d (%x)", buffer[i].name, buffer[i].surname, &day, &month, &year, &value);
            buffer[i].bity.bit.d = day;
            buffer[i].bity.bit.m = month;
            buffer[i].bity.bit.y = year;
            //buffer[i].bity.value = value;
        }
    }
    
    int main() {
        struct structure data[10];
        readfile("birthdays.txt", data, 10);
        for (int i = 0; i < 10; ++i) {
            printf("%s %s, %d/%d/%d (%x)\n", data[i].name, data[i].surname, data[i].bity.bit.d,
                data[i].bity.bit.m, data[i].bity.bit.y, data[i].bity.value);
        }
    }
    

    请注意,我在这里使用了 2 个部分名称,例如“Ethan Downey_Jr.”,但没有将 '_' 替换为 ' '。但这并不难实现。

    玩得开心,祝你好运,我希望这会有所帮助。

    【讨论】:

    • 另外,您会看到我在填充字符串之前对字符串进行了 memset。这是必要的,因为 printf 会一直打印到 '\0' 字符为止。因此,如果字符串在读入之前用 '\0' 填充,则名称后面会有 0,而不是一些垃圾。
    • 如果文件实际上是..二进制文件怎么办?
    • 好吧,我不确定 fscanf 是否适用于二进制文件。我真的不明白为什么包含文本的文件会是二进制文件,但在最坏的情况下,您可以一次读取一个字节的文件。当然只有当你使用 1 字节字符编码时,所以没有花哨的字符。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-16
    • 2018-09-28
    相关资源
    最近更新 更多