Elo*_*din 1 c arrays pointers scanf buffer-overflow
我编写了以下程序,用于将文件中的字符串读入变量"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;
}
Run Code Online (Sandbox Code Playgroud)
上面的程序在第二次调用时崩溃了fscanf.为什么会这样?
您的主要问题是您没有为要读取的字符串分配空间.您可以通过多种方式执行此操作:
char title[256];
Run Code Online (Sandbox Code Playgroud)
要么:
char *title = malloc(256);
if (title == NULL)
{
fprintf(stderr, "Out of memory\n");
exit(1);
}
Run Code Online (Sandbox Code Playgroud)
其中任何一个都应该用于:
if (fscanf(fp, " <%255[^>]>", title) != 1)
{
fprintf(stderr, "Oops: format error\n");
exit(1);
}
Run Code Online (Sandbox Code Playgroud)
或者,如果您的系统具有fscanf()与POSIX 2008兼容的实现,您可以使用m修饰符%s(或者使用%c,或者,在本例中为扫描集%[...]- 更多内容如下):
char *title = 0;
if (fscanf(fp, " <%m[^>]>", &title) != 1) // Note the crucial &
{
fprintf(stderr, "Oops: format error\n");
exit(1);
}
Run Code Online (Sandbox Code Playgroud)
这样,如果整个fscanf()成功,该函数将为标题分配内存.如果失败,则内存将被释放(或从未分配).
请注意,我换%s到%m[^>].这是必要的,因为原始转换永远不会匹配>.如果>输入中有a ,它将被合并到结果字符串中,因为它读取到空白区域,而>不是空白区域.此外,您将无法判断尾随上下文是否曾匹配 - 这是>原始格式,并且在我建议的修订代码中仍然存在问题(或不存在).
我还在字符串的开头添加了一个空格来匹配可选的空格.没有它,<字符串开头必须>与第二个数字后面的行相同,假设它>完全存在.你还应该检查第一个回报fscanf():
if (fscanf(fp, "<%d>\n<%d>", &m, &b) != 2)
{
fprintf(stderr, "Oops: format error\n");
exit(1);
}
Run Code Online (Sandbox Code Playgroud)
请注意,嵌入式换行只是查找>和之间的<空白 - 即零或多个空格,制表符或换行符.另请注意,您永远不会知道第二个>是否匹配.
你可以使用exit(EXIT_FAILURE);代替exit(1);-或者,因为这代码是main(),你可以使用两种return 1;或return(EXIT_FAILURE);其中括号是在两种情况下可选的,但它们的存在唤起某些人无端的愤怒.
您还可以改进错误消息.您应该考虑使用fgets()或getline()后面使用POSIX ,sscanf()因为它可以更容易(到目前为止)进行良好的错误报告,而且如果第一次尝试转换数据失败,您可以轻松地重新扫描数据.