我编写了以下程序,用于将文件中的字符串读入变量“title”:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int m, b;
char *title;
FILE *fp;
fp = fopen("input2.txt", "r");
if (fp == NULL)
{
printf ("Error: file cannot be found\n");
return 1;
}
fscanf(fp, "<%d>\n<%d>", &m, &b);
printf("%d\n%d", m, b);
fscanf(fp, "<%s>", title);
fclose(fp);
return 0;
}
上述程序在第二次调用fscanf
时崩溃。为什么会这样?
答案 0 :(得分:5)
您的主要问题是您没有为要读取的字符串分配空间。您可以通过多种方式执行此操作:
char title[256];
或:
char *title = malloc(256);
if (title == NULL)
{
fprintf(stderr, "Out of memory\n");
exit(1);
}
其中任何一个都应该用于:
if (fscanf(fp, " <%255[^>]>", title) != 1)
{
fprintf(stderr, "Oops: format error\n");
exit(1);
}
或者,如果您的系统的实施符合fscanf()
符合POSIX 2008,则可以使用m
修饰符%s
(或%c
1}},或者,在这种情况下,扫描集%[...]
- 更多内容如下:
char *title = 0;
if (fscanf(fp, " <%m[^>]>", &title) != 1) // Note the crucial &
{
fprintf(stderr, "Oops: format error\n");
exit(1);
}
这样,如果fscanf()
完全成功,该函数将为标题分配内存。如果失败,则内存将被释放(或从未分配)。
请注意,我将%s
更改为%m[^>]
。这是必要的,因为原始转化永远不会与>
匹配。如果输入中有>
,它将被合并到结果字符串中,因为它会读取空格,>
不是空格。此外,您无法判断尾随上下文是否匹配 - 原始格式中的>
,并且它仍然是一个问题(或不是)修改后的代码我建议。
我还在字符串的开头添加了一个空格以匹配可选的空格。如果不这样,字符串开头的<
必须与第二个数字后的>
在同一行,假设>
完全存在。您还应该检查第一个fscanf()
的回复:
if (fscanf(fp, "<%d>\n<%d>", &m, &b) != 2)
{
fprintf(stderr, "Oops: format error\n");
exit(1);
}
请注意,嵌入式换行只是查找>
和<
之间的空白区域 - 即零个或多个空格,制表符或换行符。另请注意,您永远不会知道第二个>
是否匹配。
您可以使用exit(EXIT_FAILURE);
代替exit(1);
- 或者,由于此代码位于main()
,您可以使用return 1;
或return(EXIT_FAILURE);
在任何一种情况下,括号都是可选的,但它们的存在在某些人中引起了无根据的愤怒。
您还可以改进错误消息。您应该考虑使用fgets()
或POSIX&#39; getline()
后跟sscanf()
因为它可以更容易(到目前为止)做出良好的错误报告,而且您可以轻松地重新扫描数据如果第一次尝试转换它失败了。
答案 1 :(得分:1)
此:
char *title;
只是一个指向char的指针。如果fscanf为其写入多个字符,则会破坏
之后发生在内存中的任何内容您需要做以下两件事之一:
char title[50]; // Holds up to 49 characters, plus termination
或者:
#include <stdlib.h>
// ...
char *title = malloc(50 * sizeof(char)); // Same capacity as above
if (title == NULL) {
// handle out of mem error
}
// ...
free (title);
第一个选项显然要简单得多,但要求你在编译时知道你的数组大小。
如果您不熟悉编程,并且尚未遇到指针和动态内存分配,请暂时坚持使用第一个选项。