我需要将二进制文件中的结构放入一个结构数组中,每个键一个结构。
这是我的结构:
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++;
}
答案 0 :(得分:2)
找到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的倍数,因此十六进制转储很好地对齐。