fscanf 是否向后移动文件指针?
Does fscanf move the file pointer backwards?
这些是我的文件的内容,'unsorted.txt' :
3 robert justin trump
这是我的代码:
#include <stdio.h>
int main(void) {
FILE *f = fopen("unsorted.txt", "r");
char n;
printf("%d\n", ftell(f));
fscanf(f, "%s", &n);
int l = n - '0';
printf("%d %d\n", l, ftell(f));
return 0;
}
执行时输出如下:
0
3 -1
为什么在第二种情况下 return -1
?它应该从 0
移动到 1
对吗?
注意:该文件可以打开,因为它如何在第一次调用时打印 0 和文件中的第一个字符而无法打开?
fscanf(f,"%s",&n);
是非常错误的,因为你声明了 char n;
(只有一个字节)。你得到了undefined behavior. Be very scared(下一次,感到羞耻)。
我推荐:
测试 fopen
不会失败:
FILE *f = fopen("unsorted.txt","r");
if (!f) { perror("fopen unsorted.txt"); exit(EXIT_FAILURE); };
声明一个合理大小的缓冲区(80 是 70 年代穿孔卡片的大小)。
char buf[80];
清除它(你想要defensive programming):
memset(buf, 0, sizeof(buf));
然后仔细阅读fscanf。多次阅读该文档。以固定大小使用它并测试它的结果:
if (fscanf(f, "%72s", buf) > 0) {
(72是PL/1打孔卡程序中可用的大小,小于80)
不要忘记阅读其他函数的文档,包括 ftell。
重要提示:
编译时包含所有警告和调试信息(gcc -Wall -Wextra -g
和 GCC),改进代码以消除警告,使用调试器 gdb
到运行它一步一步来。
PS。作为练习,找到 unsorted.txt
的可能内容,这些内容使您的初始程序 运行 正确。在那种情况下,你能预测它的输出吗?如果不是,为什么??
您的代码中存在多个问题:
您没有测试 fopen()
的 return 值。使用 NULL
指针调用 ftell()
具有未定义的行为。您无法从观察到的行为中得出结论。
printf("%d\n", ftell(f));
不正确,因为 ftell()
的 return 值是 long
。您应该使用格式 %ld
.
fscanf(f, "%s", &n);
是不正确的,因为您为 fscanf()
传递了单个 char
的地址来存储以 null 结尾的字符串。 fscanf()
将访问超出 char
大小的内存,这具有未定义的行为。定义一个char
的数组,比如char buf[80];
,传最大字符数存储为:fscanf(f, "%79s", buf);
,检查return值,或者用%c
读取一个字节。
int l = n - '0';
并不是严格意义上的错误,但它很容易出错:避免将变量命名为 l
,因为它看起来与 1
.[=36 容易混淆=]
printf("%d %d\n", l, ftell(f));
与之前对 printf
的调用不正确:对 [=13= 的 return 值使用转换说明符 %ld
].
另请注意,文本流中 ftell()
的 return 值不一定是文件中的字节偏移量。
这是更正后的版本:
#include <stdio.h>
int main(void) {
FILE *f = fopen("unsorted.txt", "r");
char c;
if (f != NULL) {
printf("%ld\n", ftell(f));
if (fscanf(f, "%c", &c) == 1) {
int diff = c - '0';
printf("%d %ld\n", diff, ftell(f));
}
}
return 0;
}
输出:
0
3 1
这些是我的文件的内容,'unsorted.txt' :
3 robert justin trump
这是我的代码:
#include <stdio.h>
int main(void) {
FILE *f = fopen("unsorted.txt", "r");
char n;
printf("%d\n", ftell(f));
fscanf(f, "%s", &n);
int l = n - '0';
printf("%d %d\n", l, ftell(f));
return 0;
}
执行时输出如下:
0
3 -1
为什么在第二种情况下 return -1
?它应该从 0
移动到 1
对吗?
注意:该文件可以打开,因为它如何在第一次调用时打印 0 和文件中的第一个字符而无法打开?
fscanf(f,"%s",&n);
是非常错误的,因为你声明了 char n;
(只有一个字节)。你得到了undefined behavior. Be very scared(下一次,感到羞耻)。
我推荐:
测试 fopen
不会失败:
FILE *f = fopen("unsorted.txt","r");
if (!f) { perror("fopen unsorted.txt"); exit(EXIT_FAILURE); };
声明一个合理大小的缓冲区(80 是 70 年代穿孔卡片的大小)。
char buf[80];
清除它(你想要defensive programming):
memset(buf, 0, sizeof(buf));
然后仔细阅读fscanf。多次阅读该文档。以固定大小使用它并测试它的结果:
if (fscanf(f, "%72s", buf) > 0) {
(72是PL/1打孔卡程序中可用的大小,小于80)
不要忘记阅读其他函数的文档,包括 ftell。
重要提示:
编译时包含所有警告和调试信息(gcc -Wall -Wextra -g
和 GCC),改进代码以消除警告,使用调试器 gdb
到运行它一步一步来。
PS。作为练习,找到 unsorted.txt
的可能内容,这些内容使您的初始程序 运行 正确。在那种情况下,你能预测它的输出吗?如果不是,为什么??
您的代码中存在多个问题:
您没有测试
fopen()
的 return 值。使用NULL
指针调用ftell()
具有未定义的行为。您无法从观察到的行为中得出结论。printf("%d\n", ftell(f));
不正确,因为ftell()
的 return 值是long
。您应该使用格式%ld
.fscanf(f, "%s", &n);
是不正确的,因为您为fscanf()
传递了单个char
的地址来存储以 null 结尾的字符串。fscanf()
将访问超出char
大小的内存,这具有未定义的行为。定义一个char
的数组,比如char buf[80];
,传最大字符数存储为:fscanf(f, "%79s", buf);
,检查return值,或者用%c
读取一个字节。int l = n - '0';
并不是严格意义上的错误,但它很容易出错:避免将变量命名为l
,因为它看起来与1
.[=36 容易混淆=]printf("%d %d\n", l, ftell(f));
与之前对printf
的调用不正确:对 [=13= 的 return 值使用转换说明符%ld
].
另请注意,文本流中 ftell()
的 return 值不一定是文件中的字节偏移量。
这是更正后的版本:
#include <stdio.h>
int main(void) {
FILE *f = fopen("unsorted.txt", "r");
char c;
if (f != NULL) {
printf("%ld\n", ftell(f));
if (fscanf(f, "%c", &c) == 1) {
int diff = c - '0';
printf("%d %ld\n", diff, ftell(f));
}
}
return 0;
}
输出:
0
3 1