2014-10-26 70 views
0

我试图让用户输入文件的路径。然后我将这个文件用fopen()打开。这里是我正在尝试的一个例子:将用户输入传递给fopen()参数c

char filename[80] = " "; 
printf("enter filenme:"); 
scanf("%s",&filename); 
FILE *fp=fopen(filename,"r"); 

我不断收到段错误:11作为终端错误。

+0

你调试? 'scanf'被调用后'filename'的值是什么?你应该使用'char filename [80] = {0};'。但是你确定有80个字符就够了吗? – 2014-10-26 22:47:57

+0

使用'scanf'时,你传给'filename'的指针是否正确? – 2014-10-26 22:49:34

+1

严格地说,你应该把'filename'而不是''filename'传递给'scanf()',因为后者的类型是'char(*)[80]',它不同于'char *','%s'预计。然而,传递的值最后是相同的,所以你应该得到编译器警告(或者你应该得到一个更好的编译器)。你输入什么作为文件名? – 2014-10-26 22:51:40

回答

2

您正在传递文件名开头地址的地址。不要使用&。它是一个数组,所以它已经是一个指向存储地址的指针。

+1

数组不是指针。 – rightfold 2014-10-26 22:56:42

+0

你是正确的,传递的内容不应该以'&'作为前缀。但是,“filename的开始地址”的含义并不十分清楚。它是数组的地址,类型为'char(*)[80]',它肯定与'scanf()'所期望的'char *'类型不匹配,但它实际上不是'地址的地址'。在数值上,它具有与'&filename [0]'和'filename'相同的值,但类型不同。 – 2014-10-26 22:57:30

+0

基本上调用:char filename [80];你正在创建一个字符数组(char *),该字符数组被预分配来存放80个字符。所以即使它没有明确地说char * [80]正在创建char *。不确定如果我解释清楚。但是,他并不需要将它设置为“”,否则他会没事的。 – 2014-10-26 23:00:40

0

当然,你会得到一个错误:你是路过的地址指针到scanf而不是指针本身:

scanf("%s",&filename); 

将其更改为

scanf("%s", filename); 

scanf("%s",&(filename[0])); 

你的问题应该消失了。

+0

不;代码传递数组的地址(而数组不是指针)。你说得对,类型不匹配。你错误的价值和后果。 – 2014-10-26 22:53:12

+0

这并不表示缓冲区的长度,因此仍然是缓冲区溢出漏洞。 – 2014-10-26 22:53:45

+0

对不准确,你是对的 - &(文件名[0])是指针 - 数组的名称是一种编程语言构造,当然 – feldmann 2014-10-26 22:57:36

2

既然你标记这个C++,你应该考虑使用std::getline读取文件名:

string filename; 
std::cout << "Enter filename: "; 
std::getline(std::cin, filename); 
std::ifstream input_file(filename, std::ifstream::in); 
// ... read from input_file .... 

如果你要读的文件名到一个固定大小的缓冲区,请确保您指定的那个长度阅读时缓冲区;否则,您的程序中存在缓冲区溢出漏洞。

+0

同意,由于问题标记为C++,因此一般而言,使用C标准I/O库是不恰当的。 – 2014-10-26 23:00:52

1

尽管传递给scanf()的参数不太正确,但我不认为这实际上是问题所在:数组地址和数组第一个字符的地址是相同的。更有可能fopen()失败,并且您从fopen()获得一个空指针,然后您可以访问它。也就是说,尝试这样的事情:

char filename[80] = {}; 
if (scanf("%79s", filename) != 1) { 
    printf("failed to read a filename\n"); 
} 
else if (FILE* fp = fopen(filename, "r")) { 
    printf("reading file '%s'\n", filename); 
} 
else { 
    printf("failed to open file '%s' for reading\n", filename); 
} 

(基于它似乎"%79s"的意见是限制读太多的字符到80个字符数组格式正确,但我不是一个C程序员,即我可能搞砸了正确的格式...)

等效采用C++会是这样这可能是可取:

std::string filename; 
if (!(std::cin >> filename)) { 
    std::cout << "failed to read a filename\n"; 
} 
else if (std::ifstream in{filename}) { 
    std::cout << "reading file '" << filename << "'\n"; 
} 
else { 
    std::cout << "failed to open file '" << filename << "' for reading\n"; 
} 
+0

供参考:'%79s'是正确的;标准I/O库是在'包含终端null的长度'的普通习语之前创建的。因此,它更像是'strlen()'。另外,我不认为你可以在'else if'语句中定义'FILE * fp'。然而,基本的诊断是可信的;可能的麻烦原因是文件未打开。 – 2014-10-26 22:59:15

+0

我认为你需要“%79 [^ \ n] s”,这样你就为'\ 0'留下了一个字符,并且你跳过了换行符(但也不是100%确定的...我通常避免使用scanf,因为它超级危险使用)。 – 2014-10-26 22:59:42