这是我的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
从文件中读取fread
27 个字节,因为这就是全部内容,并且 sizeof (var) 大于 2 x 15,对于 int + 4,可能还有 2 个填充)。fread
返回读取的字节数,您通常会检查该计数。
fread
不知道它void *ptr
代表什么:它不知道它是一个struct info
.它不会删除换行符,不会以\0
NUL 字符终止字符串,也不会将数字字符串转换为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 开始,并输出另一个未终止的字符串。