"Segmentation fault: 11" 在 C 中使用 fgets 时
"Segmentation fault: 11" when using fgets in C
我正在用 C 编写一个命令行工具来控制 UNDERTALE 保存文件(因为为什么不呢),每当我从用户那里获取输入时,我总是遇到分段错误。
这是我的全部代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#define KILOBYTE 1024
/* The 'm()' is so i know what line the fault happens on */
void m(void) {
printf("X");
}
int main(int argc, char**argv) {
FILE *file;
if (file = fopen("~/.undersave", "r")) {
// Do some code that I haven't written yet
}
else {
char path[KILOBYTE] = "";
printf("It seems that this is your fist time using UNDERSAVE.\nWe just need to go through some quick installation steps.\nWhere do you want your UNDERTALE save folder to be located? >>> ");
m();
fgets(path, KILOBYTE, stdin);
/*
The fault happens here, when it asks me,
i put in the input like normal, but
when I press enter, I get a fault before
it prints 'X'
*/
m();
mkdir(path, 0777);
m();
file = fopen("~/.undersave", "w");
m();
fprintf(file, "%s", path);
m();
fclose(file);
}
return 0;
}
很可能两次调用 fopen
都失败了,因为在类 Unix 系统上 ~
-扩展是 shell 的一个特性,并不应用于程序打开直接使用 fopen
或 open
的文件。如果你想打开一个相对于你的主目录的文件,要么包含完整路径,要么使用 getenv
读取 HOME
环境变量并在你的程序中构建路径。或者,更好的是,将文件名作为命令行参数;这些参数在您的程序看到它们之前由 shell 展开,因此 ~
展开就可以了。
所以 fopen
用于写入 returns NULL,您不对其进行测试(更严重的错误)。然后你尝试 fprintf
到一个空文件指针,这自然会崩溃。
此外,您的 printf("X")
不是一个好的诊断方法,因为到终端的输出通常是经过缓冲的。直到打印出新的一行,或者直到您尝试从标准输入读取,或者出现其他一些特殊情况,X 才会真正被写入屏幕。所以我怀疑程序实际上比你想象的更晚崩溃,在 fprintf
而不是 fgets
。请参阅 Why does printf not flush after the call unless a newline is in the format string?,然后将 fflush(stdout)
放在 m()
函数中的 printf
之后。
我正在用 C 编写一个命令行工具来控制 UNDERTALE 保存文件(因为为什么不呢),每当我从用户那里获取输入时,我总是遇到分段错误。
这是我的全部代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#define KILOBYTE 1024
/* The 'm()' is so i know what line the fault happens on */
void m(void) {
printf("X");
}
int main(int argc, char**argv) {
FILE *file;
if (file = fopen("~/.undersave", "r")) {
// Do some code that I haven't written yet
}
else {
char path[KILOBYTE] = "";
printf("It seems that this is your fist time using UNDERSAVE.\nWe just need to go through some quick installation steps.\nWhere do you want your UNDERTALE save folder to be located? >>> ");
m();
fgets(path, KILOBYTE, stdin);
/*
The fault happens here, when it asks me,
i put in the input like normal, but
when I press enter, I get a fault before
it prints 'X'
*/
m();
mkdir(path, 0777);
m();
file = fopen("~/.undersave", "w");
m();
fprintf(file, "%s", path);
m();
fclose(file);
}
return 0;
}
很可能两次调用 fopen
都失败了,因为在类 Unix 系统上 ~
-扩展是 shell 的一个特性,并不应用于程序打开直接使用 fopen
或 open
的文件。如果你想打开一个相对于你的主目录的文件,要么包含完整路径,要么使用 getenv
读取 HOME
环境变量并在你的程序中构建路径。或者,更好的是,将文件名作为命令行参数;这些参数在您的程序看到它们之前由 shell 展开,因此 ~
展开就可以了。
所以 fopen
用于写入 returns NULL,您不对其进行测试(更严重的错误)。然后你尝试 fprintf
到一个空文件指针,这自然会崩溃。
此外,您的 printf("X")
不是一个好的诊断方法,因为到终端的输出通常是经过缓冲的。直到打印出新的一行,或者直到您尝试从标准输入读取,或者出现其他一些特殊情况,X 才会真正被写入屏幕。所以我怀疑程序实际上比你想象的更晚崩溃,在 fprintf
而不是 fgets
。请参阅 Why does printf not flush after the call unless a newline is in the format string?,然后将 fflush(stdout)
放在 m()
函数中的 printf
之后。