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

发布于 2024-08-24 12:14:15 字数 1408 浏览 8 评论 0原文

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

该文件是二进制的,这是它的定义:

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

程序工作的方式,它将存储结构,然后是姓名,然后是地址。名称和地址是动态分配的,这就是为什么需要首先读取结构体以找到名称和地址的大小,为它们分配内存,然后将它们读入该内存。

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

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

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

fwrite(&record,sizeof record,1,fp);
fwrite(record.name,sizeof(char),record.nameLength,fp);
fwrite(record.address,sizeof(char),record.addressLength,fp);

然后我关闭该文件。 这是我读取文件的方式:

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);

注意其中有一些调试内容(名称长度和数量,两者都是正确的)。所以我知道文件正确打开,并且我可以很好地使用名称长度。那么为什么我的输出是空白,或者是换行符,或者类似的东西? (输出只是名称:后面没有任何内容,程序完成得很好)

感谢您的帮助。

I've been working on this assignment, where I need to read in "records" and write them to a file, and then have the ability to read/find them later. On each run of the program, the user can decide to write a new record, or read an old record (either by Name or #)

The file is binary, here is its definition:

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

The way the program works, it will store the structure, then the name, then the address. Name and address are dynamically allocated, which is why it is necessary to read the structure first to find the size of the name and address, allocate memory for them, then read them into that memory.

For debugging purposes I have two programs at the moment. I have my file writing program, and file reading.

My actual problem is this, when I read a file I have written, i read in the structure, print out the phone # to make sure it works (which works fine), and then fread the name (now being able to use record.nameLength which reports the proper value too).
Fread however, does not return a usable name, it returns blank.

I see two problems, either I haven't written the name to the file correctly, or I haven't read it in correctly.
Here is how i write to the file: where fp is the file pointer. record.name is a proper value, so is record.nameLength. Also i am writing the name including the null terminator. (e.g. 'Jack\0')

fwrite(&record,sizeof record,1,fp);
fwrite(record.name,sizeof(char),record.nameLength,fp);
fwrite(record.address,sizeof(char),record.addressLength,fp);

And i then close the file.
here is how i read the file:

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);

Notice there is some debug stuff in there (name length and number, both of which are correct). So i know the file opened properly, and I can use the name length fine. Why then is my output blank, or a newline, or something like that? (The output is just Name: with nothing after it, and program finishes just fine)

Thanks for the help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

耶耶耶 2024-08-31 12:14:15

我尝试了你的代码,效果很好。按顺序,这里是输出、文件的十六进制转储以及要编译的源代码。

更新:更新了代码以从标准输入或命令行参数读取名称和地址。

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;
}

I tried your code and it worked fine. In order, here is the output, a hexdump of the file, and your source made to compile.

Update: Updated code to read name and address from stdin or command-line arguments.

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;
}
壹場煙雨 2024-08-31 12:14:15

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

I would like to add my input....since you are dumping the memory structure to disk, the pointer addresses used to hold the data would most certainly be valid prior to dumping, but when reading from them, the pointer addresses could be invalid....which would explain why the character pointer is not showing the name...

三岁铭 2024-08-31 12:14:15

首先,有一点挑剔:你永远不需要 sizeof (char) - 根据定义,它总是 1。

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

我从来不喜欢在文件中读取或写入二进制数据块(例如结构体)。要意识到,通过这样做,您就向您的程序承诺,它只会读取在同一平台上编写的内容。例如,您无法在 64 位主机上写入文件并在 16 位微波炉控制器上读回该文件。

Firstly, a nitpick: you never need sizeof (char) - it's 1, always, by definition.

As for the blank name output: do you perhaps need a newline after the %s to flush the output? I've seen weird behaviour when you leave this out, and you don't state which platform you are using. If the platform's printf() is implemented bizarrely enough, you could have the format string printed and flushed, but the name itself stuck in the C library's buffers when your program exits.

And I'm never happy about reading or writing blobs of binary data like a struct to and from files. Realise that by doing so you're promising your program that it will only ever read what it wrote on the same platform. You couldn't write a file on, say, a 64-bit host and read the file back in on a 16-bit microwave oven controller.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文