C Fread二进制文件动态大小字符串

C Fread二进制文件动态大小字符串,c,fread,structure,C,Fread,Structure,我一直在做这个作业,我需要读入“记录”并将它们写入文件,然后才能在以后读取/查找它们。在每次运行程序时,用户可以决定写入新记录,或读取旧记录(通过名称或#) 该文件为二进制文件,其定义如下: typedef struct{ char * name; char * address; short addressLength, nameLength; int phoneNumber; }employeeRecord; em

我一直在做这个作业,我需要读入“记录”并将它们写入文件,然后才能在以后读取/查找它们。在每次运行程序时,用户可以决定写入新记录,或读取旧记录(通过名称或#)

该文件为二进制文件,其定义如下:

typedef struct{
        char * name;
        char * address;
        short addressLength, nameLength;
        int phoneNumber;
    }employeeRecord;
    employeeRecord record;
按照程序的工作方式,它将存储结构、名称和地址。名称和地址是动态分配的,这就是为什么必须首先读取结构以找到名称和地址的大小,为它们分配内存,然后将它们读入该内存

为了调试的目的,我现在有两个程序。我有我的文件写入程序和文件读取程序

我的实际问题是,当我读我写的文件时,我会读入结构,打印出手机#以确保它工作正常(工作正常),然后重新读取名称(现在可以使用record.nameLength报告正确的值)。 但是,Fread不返回可用的名称,它返回空白

我看到两个问题,要么我没有正确地将名称写入文件,要么我没有正确地读取它。 下面是我写入文件的方式:其中fp是文件指针。record.name和record.nameLength都是正确的值。此外,我写的名称包括空终止符。(例如“Jack\0”)

然后我关闭文件。 下面是我如何读取该文件的:

fp = fopen("employeeRecord","r");


fread(&record,sizeof record,1,fp);
printf("Number: %d\n",record.phoneNumber);


char *nameString = malloc(sizeof(char)*record.nameLength);

printf("\nName Length: %d",record.nameLength);
fread(nameString,sizeof(char),record.nameLength,fp);
printf("\nName: %s",nameString);
请注意,其中有一些调试内容(名称长度和编号,两者都是正确的)。因此,我知道文件已正确打开,并且可以使用名称长度。为什么我的输出是空的,或者换行符,或者类似的东西?(输出只是名称:后面没有任何内容,程序完成得很好)


感谢您的帮助。

我想添加我的输入…由于您正在将内存结构转储到磁盘,因此用于保存数据的指针地址在转储之前肯定是有效的,但在从中读取数据时,指针地址可能无效…这就解释了为什么字符指针没有显示名称…

我尝试了你的代码,效果很好。按照顺序,这里是输出、文件的hextump和要编译的源代码

更新:更新代码以从stdin或命令行参数读取名称和地址

prompt$ g++ -g -Wall -o test_records test_records.cpp
prompt$ echo -e "Test User\nSomeplace, Somewhere" | ./test_records
sizeof(employeeRecord) = 24
Number: 5551212

Name Length: 9
Name: Test User

prompt$ hexdump -C employeeRecord 
00000000  90 f7 bf 5f ff 7f 00 00  70 f7 bf 5f ff 7f 00 00  |..._....p.._....|
00000010  14 00 09 00 6c b4 54 00  54 65 73 74 20 55 73 65  |....l.T.Test Use|
00000020  72 53 6f 6d 65 70 6c 61  63 65 2c 20 53 6f 6d 65  |rSomeplace, Some|
00000030  77 68 65 72 65                                    |where|
00000035

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

typedef struct{
        char * name;
        char * address;
        short addressLength, nameLength;
        int phoneNumber;
    }employeeRecord;

int main(int argc, char *argv[])
{
  employeeRecord record;

#if 0
  // Commmand line arguments
  if (argc < 3)
    return 1;

  record.nameLength = strlen(argv[1]);
  record.name = (char *)malloc(sizeof(char)*(record.nameLength + 1));
  strncpy(record.name, argv[1], record.nameLength + 1);

  record.addressLength = strlen(argv[2]);
  record.address = (char *)malloc(sizeof(char)*(record.addressLength + 1));
  strncpy(record.address, argv[2], record.addressLength + 1);
#else
  // stdin
  char input[1024];

  fgets(input, sizeof(input), stdin);
  record.nameLength = strlen(input);
  record.name = (char *)malloc(sizeof(char)*(record.nameLength + 1));
  strncpy(record.name, input, record.nameLength + 1);

  fgets(input, sizeof(input), stdin);
  record.addressLength = strlen(input);
  record.address = (char *)malloc(sizeof(char)*(record.addressLength + 1));
  strncpy(record.address, input, record.addressLength + 1);
#endif

  record.phoneNumber = 5551212;

  FILE *fp = NULL;

  printf("sizeof(employeeRecord) = %lu\n", sizeof(employeeRecord));

  // Write
  fp = fopen("employeeRecord","w");
  fwrite(&record,sizeof(employeeRecord),1,fp);
  // Note: we're not including terminating NULLs.
  fwrite(record.name,sizeof(char),record.nameLength,fp);
  fwrite(record.address,sizeof(char),record.addressLength,fp);
  fclose(fp);

  // Read
  fp = fopen("employeeRecord","r");
  fread(&record,sizeof(employeeRecord),1,fp);
  printf("Number: %d\n",record.phoneNumber);

  char *nameString = (char *)malloc(sizeof(char)*(record.nameLength + 1));
  printf("\nName Length: %d",record.nameLength);
  fread(nameString,sizeof(char),record.nameLength,fp);
  nameString[record.nameLength] = '\0';
  printf("\nName: %s",nameString);
  printf("\n");

  fclose(fp);

  return 0;
}
prompt$g++-g-Wall-o test\u records test\u records.cpp
提示$echo-e“测试用户\n某处某处”|/Test_记录
sizeof(员工记录)=24
电话:5551212
姓名长度:9
名称:测试用户
提示$hextump-C employeeRecord
00000000 90 f7高炉5f ff 7f 00 70 f7高炉5f ff 7f 00|
000000 10 14 00 09 00 6c b4 54 00 54 65 73 74 20 55 73 65 |…l.T.试验使用|
000000 20 72 53 6f 6d 65 70 6c 61 63 65 2c 20 53 6f 6d 65 |有些地方|
000000 30 77 68 65 72 65 |其中|
00000035
#包括
#包括
#包括
类型定义结构{
字符*名称;
字符*地址;
短地址长度,名称长度;
整数音素;
}员工档案;
int main(int argc,char*argv[])
{
员工记录;
#如果0
//命令行参数
如果(argc<3)
返回1;
record.nameLength=strlen(argv[1]);
record.name=(char*)malloc(sizeof(char)*(record.nameLength+1));
strncpy(record.name,argv[1],record.nameLength+1);
record.addressLength=strlen(argv[2]);
record.address=(char*)malloc(sizeof(char)*(record.addressLength+1));
strncpy(record.address,argv[2],record.addressLength+1);
#否则
//标准
字符输入[1024];
fgets(输入,sizeof(输入),标准输入);
record.nameLength=strlen(输入);
record.name=(char*)malloc(sizeof(char)*(record.nameLength+1));
strncpy(record.name,输入,record.nameLength+1);
fgets(输入,sizeof(输入),标准输入);
record.addressLength=strlen(输入);
record.address=(char*)malloc(sizeof(char)*(record.addressLength+1));
strncpy(record.address,input,record.addressLength+1);
#恩迪夫
record.phoneNumber=5551212;
FILE*fp=NULL;
printf(“sizeof(employeeRecord)=%lu\n”,sizeof(employeeRecord));
//写
fp=fopen(“员工记录”,“w”);
fwrite(和record,sizeof(employeeRecord),1,fp);
//注意:我们不包括终止空值。
fwrite(record.name,sizeof(char),record.nameLength,fp);
fwrite(record.address,sizeof(char),record.addressLength,fp);
fclose(fp);
//阅读
fp=fopen(“员工记录”,“r”);
fread(&record,sizeof(employeeRecord),1,fp);
printf(“号码:%d\n”,record.phoneNumber);
char*nameString=(char*)malloc(sizeof(char)*(record.nameLength+1));
printf(“\n名称长度:%d”,记录.名称长度);
fread(nameString,sizeof(char),record.nameLength,fp);
nameString[record.nameLength]='\0';
printf(“\n名称:%s”,名称字符串);
printf(“\n”);
fclose(fp);
返回0;
}

首先,一个吹毛求疵的问题:你永远不需要sizeof(char)-根据定义,它总是1

空白名称输出:在%s之后刷新输出是否需要换行符?我看到过一些奇怪的行为,当你忽略了这一点,并且你没有说明你正在使用哪个平台时。如果平台的printf()实现得足够离奇,则可以打印并刷新格式字符串,但当程序退出时,名称本身会卡在C库的缓冲区中


我从不喜欢在文件中读写二进制数据,比如结构。要意识到,这样做意味着你向你的程序承诺,它只会在同一平台上阅读它所写的内容。您不能在64位主机上写入文件,也不能在16位微波炉控制器上读回文件。

(挑剔:有些电话号码可能超过10位,或者包含
#
*
)您检查过fread()的返回值吗?检查文件中的内容,例如十六进制viewer@KennyTM对但是对于这个练习,假设它是一个适合int的小数字。将检查
prompt$ g++ -g -Wall -o test_records test_records.cpp
prompt$ echo -e "Test User\nSomeplace, Somewhere" | ./test_records
sizeof(employeeRecord) = 24
Number: 5551212

Name Length: 9
Name: Test User

prompt$ hexdump -C employeeRecord 
00000000  90 f7 bf 5f ff 7f 00 00  70 f7 bf 5f ff 7f 00 00  |..._....p.._....|
00000010  14 00 09 00 6c b4 54 00  54 65 73 74 20 55 73 65  |....l.T.Test Use|
00000020  72 53 6f 6d 65 70 6c 61  63 65 2c 20 53 6f 6d 65  |rSomeplace, Some|
00000030  77 68 65 72 65                                    |where|
00000035

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

typedef struct{
        char * name;
        char * address;
        short addressLength, nameLength;
        int phoneNumber;
    }employeeRecord;

int main(int argc, char *argv[])
{
  employeeRecord record;

#if 0
  // Commmand line arguments
  if (argc < 3)
    return 1;

  record.nameLength = strlen(argv[1]);
  record.name = (char *)malloc(sizeof(char)*(record.nameLength + 1));
  strncpy(record.name, argv[1], record.nameLength + 1);

  record.addressLength = strlen(argv[2]);
  record.address = (char *)malloc(sizeof(char)*(record.addressLength + 1));
  strncpy(record.address, argv[2], record.addressLength + 1);
#else
  // stdin
  char input[1024];

  fgets(input, sizeof(input), stdin);
  record.nameLength = strlen(input);
  record.name = (char *)malloc(sizeof(char)*(record.nameLength + 1));
  strncpy(record.name, input, record.nameLength + 1);

  fgets(input, sizeof(input), stdin);
  record.addressLength = strlen(input);
  record.address = (char *)malloc(sizeof(char)*(record.addressLength + 1));
  strncpy(record.address, input, record.addressLength + 1);
#endif

  record.phoneNumber = 5551212;

  FILE *fp = NULL;

  printf("sizeof(employeeRecord) = %lu\n", sizeof(employeeRecord));

  // Write
  fp = fopen("employeeRecord","w");
  fwrite(&record,sizeof(employeeRecord),1,fp);
  // Note: we're not including terminating NULLs.
  fwrite(record.name,sizeof(char),record.nameLength,fp);
  fwrite(record.address,sizeof(char),record.addressLength,fp);
  fclose(fp);

  // Read
  fp = fopen("employeeRecord","r");
  fread(&record,sizeof(employeeRecord),1,fp);
  printf("Number: %d\n",record.phoneNumber);

  char *nameString = (char *)malloc(sizeof(char)*(record.nameLength + 1));
  printf("\nName Length: %d",record.nameLength);
  fread(nameString,sizeof(char),record.nameLength,fp);
  nameString[record.nameLength] = '\0';
  printf("\nName: %s",nameString);
  printf("\n");

  fclose(fp);

  return 0;
}