c - 将二进制文件构造成数组 C

标签 c arrays struct binaryfiles

我需要将二进制文件中的结构放入结构数组中,每个键一个结构。

这是我的结构:

struct candidate{
    char inscr[10];
    char name[44];
    int year;
    int position;
    char curse[30];
};
typedef struct candidate Candidate;

这是我尝试做的:

void ordenafile(char fname[13]){
FILE *f = fopen (fname, "rb");
if(f==NULL){
    printf("Error.");
return;
}
fseek(f, 0, SEEK_END);
int  sz = ftell(f);
Candidate *p, *aux,*arr[sz/sizeof(Candidate)];
p=(Candidate*)malloc(sizeof(Candidate));
int i = 0;
while(fread(p,sizeof(candidate),1,f)>0){
    arr[i]=p;
    i++;
}

最佳答案

使用 fseek() 找到文件末尾后,您需要在读取之前倒回。

这部分代码没有达到您想要的效果:

Candidate *p, *aux,*arr[sz/sizeof(Candidate)];
p=(Candidate*)malloc(sizeof(Candidate));
int i = 0;
while(fread(p,sizeof(candidate),1,f)>0){
    arr[i]=p;
    i++;
}

您有一个结构体指针数组,并且分配了一个由p 指向的结构体。然后,循环将一个值读取到一个结构中,并将指针复制到指针数组的一个元素中。因此,数组的所有元素都指向相同的结构。变量 aux 也未使用。

您需要以下两种解决方案之一:

Candidate arr[sz/sizeof(Candidate)];
int i;
for (i = 0; fread(&arr[i], sizeof(Candidate), 1, f) == 1; i++)
    ;

这假设您将能够在当前函数及其调用的函数中使用该数组,并且不需要将其返回给调用代码。

或者:

Candidate *arr = malloc(sz);
if (arr == 0)
    return 0;
int i;
for (i = 0; fread(&arr[i], sizeof(Candidate), 1, f) == 1; i++)
    ;

return arr;

您可以从函数返回该数组。

<小时/>

工作代码

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

struct candidate
{
    char inscr[10];
    char name[44];
    int year;
    int position;
    char curse[30];
};
typedef struct candidate Candidate;

int write_sample_data(const char *filename);
Candidate *read_sample_data(const char *filename, int *number);
void print_sample_data(int num, Candidate *candidates);

int main(void)
{
    const char filename[] = "practice.data";

    if (write_sample_data(filename) != 0)
        fprintf(stderr, "Failed to write sample data\n");
    else
    {
        int number = 0;
        Candidate *clist = read_sample_data(filename, &number);
        if (number == 0)
            fprintf(stderr, "Failed to read sample data\n");
        else
        {
            print_sample_data(number, clist);
            free(clist);
        }
    }
    return 0;
}

int write_sample_data(const char *filename)
{
    FILE *fp = fopen(filename, "wb");
    if (fp == NULL)
    {
        fprintf(stderr, "Failed to open file %s for writing\n", filename);
        return -1;
    }
    Candidate c;
    for (int i = 0; i < 5; i++)
    {
        char inscr[10];
        char name[40];
        char curse[30];
        sprintf(inscr, "I-%.4d", i);
        sprintf(name, "Name %.4d Surname %.4d", rand() % 1000, rand() % 1000);
        sprintf(curse, "Curse %.2d", rand() % 100);
        // Using null-filling property of strncpy()
        strncpy(c.inscr, inscr, sizeof(c.inscr));
        strncpy(c.name, name, sizeof(c.name));
        strncpy(c.curse, curse, sizeof(c.curse));
        c.year = 2010 + i;
        c.position = 1000 * i + (99 - i);
        if (fwrite(&c, sizeof(Candidate), 1, fp) != 1)
        {
            fclose(fp);
            fprintf(stderr, "Failed to write candidate %d\n", i);
            return -1;
        }
    }
    fclose(fp);
    return 0;
}

Candidate *read_sample_data(const char *filename, int *number)
{
    FILE *fp = fopen(filename, "rb");

    if (fp == NULL)
    {
        fprintf(stderr, "Failed to open file %s for reading\n", filename);
        return 0;
    }
    fseek(fp, 0, SEEK_END);
    size_t sz = ftell(fp);
    rewind(fp);

    Candidate *arr = malloc(sz);
    if (arr == 0)
    {
        fprintf(stderr, "Failed to allocate %zu bytes memory\n", sz);
        return 0;
    }

    int i;
    for (i = 0; fread(&arr[i], sizeof(Candidate), 1, fp) == 1; i++)
        ;

    *number = i;
    return arr;
}

void print_sample_data(int number, Candidate *clist)
{
    for (int i = 0; i < number; i++)
    {
        printf("%-10s %-30s %.4d %.4d %s\n",
               clist[i].inscr, clist[i].name, clist[i].year,
               clist[i].position, clist[i].curse);
    }
}

请注意,尽管使用了 rand() 中的伪随机数,但每次运行都会生成相同的数据。另请注意,代码故意利用 strncpy() 的行为,将空字节填充到完整长度,以便文件中的数据没有任何无关的内容。

示例输出:

I-0000     Name 0249 Surname 0807         2010 0099 Curse 73
I-0001     Name 0930 Surname 0658         2011 1098 Curse 72
I-0002     Name 0878 Surname 0544         2012 2097 Curse 23
I-0003     Name 0440 Surname 0709         2013 3096 Curse 65
I-0004     Name 0042 Surname 0492         2014 4095 Curse 87

数据文件的十六进制转储:

0x0000: 49 2D 30 30 30 30 00 00 00 00 4E 61 6D 65 20 30   I-0000....Name 0
0x0010: 32 34 39 20 53 75 72 6E 61 6D 65 20 30 38 30 37   249 Surname 0807
0x0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0030: 00 00 00 00 00 00 00 00 DA 07 00 00 63 00 00 00   ............c...
0x0040: 43 75 72 73 65 20 37 33 00 00 00 00 00 00 00 00   Curse 73........
0x0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0060: 49 2D 30 30 30 31 00 00 00 00 4E 61 6D 65 20 30   I-0001....Name 0
0x0070: 39 33 30 20 53 75 72 6E 61 6D 65 20 30 36 35 38   930 Surname 0658
0x0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0090: 00 00 00 00 00 00 00 00 DB 07 00 00 4A 04 00 00   ............J...
0x00A0: 43 75 72 73 65 20 37 32 00 00 00 00 00 00 00 00   Curse 72........
0x00B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x00C0: 49 2D 30 30 30 32 00 00 00 00 4E 61 6D 65 20 30   I-0002....Name 0
0x00D0: 38 37 38 20 53 75 72 6E 61 6D 65 20 30 35 34 34   878 Surname 0544
0x00E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x00F0: 00 00 00 00 00 00 00 00 DC 07 00 00 31 08 00 00   ............1...
0x0100: 43 75 72 73 65 20 32 33 00 00 00 00 00 00 00 00   Curse 23........
0x0110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0120: 49 2D 30 30 30 33 00 00 00 00 4E 61 6D 65 20 30   I-0003....Name 0
0x0130: 34 34 30 20 53 75 72 6E 61 6D 65 20 30 37 30 39   440 Surname 0709
0x0140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0150: 00 00 00 00 00 00 00 00 DD 07 00 00 18 0C 00 00   ................
0x0160: 43 75 72 73 65 20 36 35 00 00 00 00 00 00 00 00   Curse 65........
0x0170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0180: 49 2D 30 30 30 34 00 00 00 00 4E 61 6D 65 20 30   I-0004....Name 0
0x0190: 30 34 32 20 53 75 72 6E 61 6D 65 20 30 34 39 32   042 Surname 0492
0x01A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x01B0: 00 00 00 00 00 00 00 00 DE 07 00 00 FF 0F 00 00   ................
0x01C0: 43 75 72 73 65 20 38 37 00 00 00 00 00 00 00 00   Curse 87........
0x01D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x01E0:

结构体中有4个字节的填充; name 之后为 2,末尾为 2,因此其长度为方便的 96 字节,恰好是 16 的倍数,因此十六进制转储可以很好地对齐。

关于c - 将二进制文件构造成数组 C,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27085643/

相关文章:

c - 结构中的填充总是相同吗?

c - 为什么这段代码没有指定访问数组的哪个元素?

c - c 中浮点值的 mod 运算符。这显示错误 "illegal use of floating point"

arrays - Swift - 无法为索引类型为 NSNumber 的值类型 [String] 下标?

javascript - 返回具有特定属性的数组中的对象

c - 包含两个指针的结构的大小

c - 如何关闭 zookeeper 日志信息?

将 8051 微 Controller 的端口 1 配置为输入

mysql - 将两个输入转换为单个数组以输入到 db codeigniter

c - 库存系统方法