为什么这个程序无法读取struct中的文本文件?

为什么这个程序无法读取struct中的文本文件?

这是我的a.txt文件,共三行。它不包含任何额外的空格或任何不可打印的字符:

David Joans
018976
David12

这是我用来C读取此文件的代码,我在其中创建了一个结构来读取它。代码::

#include<stdio.h>
#include<stdlib.h>
        
#pragma pack(1)
        
typedef struct info {
  char name[15];
  int num;
  char pass[15];
}info;
        
int main(int argc, char const* argv[])
{
  FILE* fp = NULL;
  if (fp = fopen("a.txt", "r")) {
    info var;
    fread(&var, 1, sizeof(var), fp);
    printf("%s\n%d\n%s\n", var.name, var.num, var.pass);
  }
  else {
    perror("File can not be opened!!\n");
    exit(EXIT_FAILURE);
  }
  return 0;
}

输出如下:

David Joans
018976
David12
171325241
David12

程序中的实际问题是什么?帮我弄清楚。

答案1

文件的二进制表示形式不需要与 struct 的实际二进制表示形式匹配info。编译器可以自由地使用结构体字段之间的填充空间。因此,执行您想要的操作的唯一可靠方法是单独读取文件中的每个字段并将其分配给结构中的相应字段。像这样的东西:

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

#pragma pack(1)

typedef struct info {
  char name[15];
  int num;
  char pass[15];
}info;

int main(int argc, char const* argv[])
{
  FILE* fp = NULL;
  if (fp = fopen("a.txt", "r")) {
    info var;
    char num_str[15];
    char *endl_ptr;

    fgets (var.name, sizeof (var.name), fp);
    fgets (num_str, sizeof (num_str), fp);
    fgets (var.pass, sizeof (var.pass), fp);

    /* parse num_str into an integer */
    var.num = strtol(num_str, NULL, 10);

    /* replace the trailing endline character by a NULL */
    if ((endl_ptr = strchr (var.name, '\n')))
        *endl_ptr = '\0';
    if ((endl_ptr = strchr (var.pass, '\n')))
        *endl_ptr = '\0';

    printf("%s\n%d\n%s\n", var.name, var.num, var.pass);
  }
  else {
    perror("File can not be opened!!\n");
    exit(EXIT_FAILURE);
  }
  return 0;
}

或者,您可以拥有一个实际二进制表示与结构中的二进制表示相匹配的文件。例如,如果文件是从已经info填充了一个结构的程序生成的,那么简单的write结构到文件就可以解决问题。然而,这不能移植到其他系统。

答案2

从文件中读取fread27 个字节,因为这就是全部内容,并且 sizeof (var) 大于 2 x 15,对于 int + 4,可能还有 2 个填充)。fread返回读取的字节数,您通常会检查该计数。

fread不知道它void *ptr代表什么:它不知道它是一个struct info.它不会删除换行符,不会以\0NUL 字符终止字符串,也不会将数字字符串转换为int.它只是将输入字节连续地涂抹在结构占用的内存空间上。

您必须使用string函数自己解析字节块strtol(这两个都有手册页)。所以你需要读入一个中间char buf [80];数组。

输出的前 3 行是整个输入:幸运的是,它没有使程序崩溃,因为它遇到了偶然的 NUL 字符。

第四行可能是字节“976D”,从 重新访问为 int info.num,并且字节顺序相反,因为您的 CPU 是小端字节序。

第五行是 re-accessing info.pass,这是输入的最后一行结束的地方。

fread(&var, 1, sizeof(var), fp);尝试从文件中获取 36 字节数据,并将它们连续存储在指针&var指定的位置。它不知道(或关心) &var 指向任何类型的结构,或者接收区域可能有多大。var仅有的内存地址——没有附加大小或类型。它也无法读取您要求的字节数,因为文本文件比sizeof(var).

经过重新访问,我的意思是printf("%s\n%d\n%s\n", var.name, var.num, var.pass);多次输出一些数据。printf被告知结构体每个部分的地址,但它仍然不知道结构体成员的类型或长度。未终止的字符串var.name得到全部输入数据。然后var.num再次从输入数据的第 16 个字节开始,占用文本的 4 个字节,并错误地认为它们是有意义的 int。然后var.pass再次从输入的字节 20 开始,并输出另一个未终止的字符串。

相关内容