C 程序可以在 gdb 中找到(通过 fopen)但不能释放(a.out)
C Program can find (via fopen) in gdb but not release (a.out)
这是一个简单的 C 程序,它读取文件位置的用户输入并打印第一行(如果存在):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
int main() {
// init vars for user input, error checking
char file[PATH_MAX];
scanf("%s", file);
errno = 0;
FILE *contents = fopen(file, "r");
// debug, check if file exists and raises error if not
if (contents == NULL || errno != 0) {
printf("Error raised: %s", strerror(errno));
exit(1);
}
char example[1024] = "";
fgets(example, 1024, contents);
printf("%s", example);
// necessary closing of the stream
fclose(contents);
return 0;
}
运行 调试 (gdb) 上的代码工作正常,我只是输入同一目录中的文件位置,它工作正常。但是 运行 像 cat file.txt | ./a.out
这样的东西是行不通的;显然,strerror()
returns No such file or directory
。我对 C 的了解还不够多,不知道未定义的行为是如何起作用的,但我所知道的是它一定与 fopen
.
有关
无论哪种方式,我只是希望有一个替代的工作解决方案,或者知道为什么调试器可以做一些可执行文件不能做的事情。
我怀疑您真正需要做的只是 echo file.txt | ./a.out
,但您的代码还有其他问题。从参数而不是标准输入中读取文件名要清晰得多。如果您确实使用 scanf
从 stdin 读取,您应该限制读取的数据量以防止缓冲区溢出,并且您必须始终检查 scanf 返回的值以了解它是否实际读取了任何数据。您不能假定 errno 的非零值表示错误。成功完成的函数没有义务避免更改 errno 并且可以将其保留为非零值。也许尝试这样的事情:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
int
main(void)
{
char file[PATH_MAX];
char fmt[64];
snprintf(fmt, sizeof fmt, "%%%ds", PATH_MAX - 1);
if( scanf(fmt, file) == 1 ){
FILE *contents = fopen(file, "r");
if( contents == NULL ) {
perror(file);
return 1;
}
char example[1024];
fgets(example, 1024, contents);
printf("%s", example);
fclose(contents);
return 0;
}
return 1;
}
但这确实是一个 很多 清洁器,可以避免 scanf 并只执行 const char *path = argv[1]
或类似操作。
请注意 scanf
和 %s
不适合此任务,因为无法读取包含空格的文件名。 fgets
也好不到哪里去,因为名称也可以包含换行符。
我不能准确地说出这个词,但是 cat
直接将 txt 的内容输入到程序中……显然它开始尝试查找一个不存在的文件。 运行 可执行文件工作,因为程序通过获取文件目录工作,然后搜索它,剩下的就是历史。
示例解决方案:运行 a scanf/fgets(无论偏好如何)直到 EOF/NULL 进入某个变量。
这是一个简单的 C 程序,它读取文件位置的用户输入并打印第一行(如果存在):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
int main() {
// init vars for user input, error checking
char file[PATH_MAX];
scanf("%s", file);
errno = 0;
FILE *contents = fopen(file, "r");
// debug, check if file exists and raises error if not
if (contents == NULL || errno != 0) {
printf("Error raised: %s", strerror(errno));
exit(1);
}
char example[1024] = "";
fgets(example, 1024, contents);
printf("%s", example);
// necessary closing of the stream
fclose(contents);
return 0;
}
运行 调试 (gdb) 上的代码工作正常,我只是输入同一目录中的文件位置,它工作正常。但是 运行 像 cat file.txt | ./a.out
这样的东西是行不通的;显然,strerror()
returns No such file or directory
。我对 C 的了解还不够多,不知道未定义的行为是如何起作用的,但我所知道的是它一定与 fopen
.
无论哪种方式,我只是希望有一个替代的工作解决方案,或者知道为什么调试器可以做一些可执行文件不能做的事情。
我怀疑您真正需要做的只是 echo file.txt | ./a.out
,但您的代码还有其他问题。从参数而不是标准输入中读取文件名要清晰得多。如果您确实使用 scanf
从 stdin 读取,您应该限制读取的数据量以防止缓冲区溢出,并且您必须始终检查 scanf 返回的值以了解它是否实际读取了任何数据。您不能假定 errno 的非零值表示错误。成功完成的函数没有义务避免更改 errno 并且可以将其保留为非零值。也许尝试这样的事情:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
int
main(void)
{
char file[PATH_MAX];
char fmt[64];
snprintf(fmt, sizeof fmt, "%%%ds", PATH_MAX - 1);
if( scanf(fmt, file) == 1 ){
FILE *contents = fopen(file, "r");
if( contents == NULL ) {
perror(file);
return 1;
}
char example[1024];
fgets(example, 1024, contents);
printf("%s", example);
fclose(contents);
return 0;
}
return 1;
}
但这确实是一个 很多 清洁器,可以避免 scanf 并只执行 const char *path = argv[1]
或类似操作。
请注意 scanf
和 %s
不适合此任务,因为无法读取包含空格的文件名。 fgets
也好不到哪里去,因为名称也可以包含换行符。
我不能准确地说出这个词,但是 cat
直接将 txt 的内容输入到程序中……显然它开始尝试查找一个不存在的文件。 运行 可执行文件工作,因为程序通过获取文件目录工作,然后搜索它,剩下的就是历史。
示例解决方案:运行 a scanf/fgets(无论偏好如何)直到 EOF/NULL 进入某个变量。