提问人:Anil 提问时间:11/23/2021 更新时间:11/24/2021 访问量:131
为什么 fscanf 读取垃圾?
Why is fscanf read garbage?
问:
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define PATH "F:\\c\\projects\\Banking Management System\\data\\"
#define F_ACCT "accounts.txt"
#define FILENAME(file) PATH file
#define F_ACCT_FPRINTF "%05d%-8s%-30s%d%d%d%-20s%-20s%-20s%c%-15.2lf\n"
#define F_ACCT_FSCANF "%05d%8s%30[^\n]%d%d%d%20[^\n]%20[^\n]%20[^\n]%c%lf\n"
typedef struct Date
{
int dd;
int mm;
int ccyy;
} Date;
typedef struct Account
{
int id;
char acct_no[8];
char name[30];
Date birthday;
char telephone_no[20];
char mobile_no[20];
char tfn[20];
char acct_type; // 'S' - Saving | 'C' - Current | Fixed - 'F' | Recurring - 'R'
double acct_bal;
} Account;
int main(int argc, char *argv[])
{
Account *ac_t=malloc(sizeof(Account));
if (ac_t==NULL)
{
free(ac_t);
perror("Fatal error: ");
exit(EXIT_FAILURE);
}
FILE *fp=fopen(FILENAME(F_ACCT),"a+"); // Save option selected by the user
if (!fp) // NULL=0=true
{
free(ac_t);
perror("ERROR:");
exit(EXIT_FAILURE);
}
(fscanf(fp,F_ACCT_FSCANF,\
&ac_t->id,\
ac_t->acct_no,\
ac_t->name,\
&ac_t->birthday.dd,\
&ac_t->birthday.mm,\
&ac_t->birthday.ccyy,\
ac_t->telephone_no,\
ac_t->mobile_no,\
ac_t->tfn,\
&ac_t->acct_type,\
&ac_t->acct_bal));
printf("\ntmp=%d", tmp);
printf("\n[%d]",ac_t->id);
printf("\n[%s]",ac_t->acct_no);
printf("\n[%s]",ac_t->name);
printf("\n[%d]",ac_t->birthday.dd);
printf("\n[%d]",ac_t->birthday.mm);
printf("\n[%d]",ac_t->birthday.ccyy);
printf("\n[%s]",ac_t->telephone_no);
printf("\n[%s]",ac_t->mobile_no);
printf("\n[%s]",ac_t->tfn);
printf("\n[%c]",ac_t->acct_type);
printf("\n[%lf]",ac_t->acct_bal);
system("pause");
free(pw_t);
return 0;
}
=========================================================================================
输入文件 (accounts: .txt) =========================
000011000 Anil Dhar 27111960(02) 8883 2827 0408 942 407 111222333 S 100.21
Note: The record was created successfully using frpintf() as per F_ACCT_FPRINTF.
**Problem**
=======
fscanf is reading garbage values like this:
ac_t->id 1
t_acct_no
name Anil Dhar
birthday.dd 27
birthday.mm 11
birthday.ccyy 1960
telephone_no (02) 8883 2827 0408 942 407 111222333 Sogram Files\Intel\ip¬tαK4
mobile_no 0408 942 407 111222333 Sogram Files\Intel\ip¬tαK4
tfn 111222333 Sogram Files\Intel\ip¬tαK4
t_acct_type
acct_bal 74895632819821970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000
我所有的字符串变量,如 name、telephone_no、mobile_no、tfn 都可以包含空格。 该记录没有用任何内容分隔。无论我在哪里读取字符串变量,我的 fscanf() 都没有正确填充字段。
可能出了什么问题????
答:
$20[^\n]
读取所有内容,直到行尾。例如,一直读到一个空格。请注意,除 和 之外的所有说明符都会自动占用并忽略前导空格(制表符、换行符和 spc)。请注意,所有空格都会自动占用并忽略零个或多个空格。请参阅 scanf 文档。无论如何,我也会撒空格以使格式更具可读性。不要添加尾随 。检查 scanf 的返回值,不要将其保留为未选中状态 - 扫描可能会失败。您最多需要读取比缓冲区少一个字符,或者您必须将缓冲区增加一个位置才能终止零字节。%[]
%c
scanf
\n
"%d %7[^ ] %29[^ ] %d %d %d %19[^ ] %19[^ ] %19[^ ] %c %lf"
%s
读取空格分隔的字符串,同时读取下一个换行符。看来你想要一个特定数量的字符,所以你想要.所以你应该有更多类似的东西:%[^\n]
%c
#define F_ACCT_FSCANF "%5d%8c%30c%2d%2d%4d%20c%20c%20c%c%lf"
我不确定这是否完全正确,因为您的打印格式有些模棱两可(使用 instead instead 意味着您不知道会得到多少位数字)。如果您的输入文件以任何方式修改了其间距,它也会严重偏离轨道,因此您可能希望使用 fgets+sscanf 而不是 fscanf,因为这至少允许您在任何损坏的行后重新同步。%d
%02d
需要注意的一件事 - 将恰好将 8 个字符读入作为参数提供的缓冲区中,其中 NO 终止 NUL - 如果您想要以 NUL 结尾的字符串,则需要手动安排。%8c
评论
fscanf
char name[30];
char [...]
%20[^\n]
它一直读取到换行符,所以它读取所有内容直到行尾。在您的例子中,字段似乎被空格分隔。输入格式是什么?