c语言 - 为什么 fopen() 无法识别我的文件名?



程序应该能够打开像myFile.txt这样的文件, 所有Tough它的真名是myFile没有扩展名.txt。 所以我按顺序写了名为removeFileExtension()function来实现这一目标。

它确实通过将stringtext复制到filename来打开我的文件:

strcpy(filename,text);
FILE *fp = fopen(filename, "r");

所以我试图检查text和我处理的有什么区别string来自removeFileExtension是。

为了检查它是否有效,我配上了一种名为strComparison()function, 当它为合格时返回0,如果不相等,则返回1。 问题是,删除文件扩展名后,它显示两个字符串 是合格的,但我仍然无法打开文件。

当我输入./a.out myFile.txt我的比较function返回0时, 它是相等的,但fopen()仍然无法打开文件, 我分别得到了一个Segmentation fault.

有人看到这里的问题吗? 为什么我要Segmentation fault

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void removeFileExtension(char *haystack);
int strComparison(char *one, char *two);
int main(int argc, char const *argv[])
{
//----------------------------------------------------------------------------
// CHECK INPUT VALIDITY
//
if (argc != 2)
{
printf("Usage: ./ass2 [file-name]n");
return 1;
}

//----------------------------------------------------------------------------
// OPEN FILE (INITIAL)
//
char filename[32];
strcpy(filename, argv[1]);
FILE *fp = fopen(filename, "r");                                       //FOPEN
//FILE *fp = fopen("start_of_storytxt", "r");   // this way does work
if (fp == NULL)
{
// IF NOT FOUND: REMOVE EXTENSION
removeFileExtension(filename);
char text[] = "myFile";
int ret_val = -1;
ret_val = strComparison(filename, text);
if (ret_val == 0)
printf("[DEBUG] equaln");
else
printf("[DEBUG] unequaln");
printf("[DEBUG] ret_val: %dn", ret_val);
printf("[DEBUG] '%s'n", filename);
FILE *fp = fopen(filename, "r");                                     //FOPEN
// IF STILL DOESN'T WORK: ERROR
if (fp == NULL)
{
printf("[ERR] Could not read file %s.n", filename);
return 3;
}
}

//--------------------------------------------------------------------------
// READ DATA (INITIAL)
//
int bufsize = 1024;
char *buffer = malloc(bufsize * sizeof(char));                      //MALLOC
if (!buffer)
{
printf("[ERR] Out of memory.n");
return 2;
}
fseek(fp, 0, SEEK_SET);
fread(buffer, bufsize, 1, fp);
printf("[DEBUG] %sn", buffer);
fclose(fp);                                                           //FCLOSE
free(buffer);
buffer = NULL;
return 0;
}
void removeFileExtension(char *haystack)
{
char needle[1] = ".";
char *retp;   // return pointer
retp = strstr(haystack,needle);
if (*retp == '.')
{
while (*retp != '')
{
*retp++ = '';
}
printf("[DEBUG] %sn", haystack);
}
}
int strComparison(char *one, char *two)
{
do
{
printf("[DEBUG] '%c' == '%c'n", *one, *two);
if (*one++ != *two++)
{
return 1; // return 1 if unqual
}
}
while ( (*one != '') || (*two != '') );
return 0; // return 0 if qual
}

结果输出:

user@host ~/Desktop $ ./a.out myFile.txt
[DEBUG] myFile
[DEBUG] 'm' == 'm'
[DEBUG] 'y' == 'y'
[DEBUG] 'F' == 'F'
[DEBUG] 'i' == 'i'
[DEBUG] 'l' == 'l'
[DEBUG] 'e' == 'e'
[DEBUG] equal
[DEBUG] ret_val: 0
[DEBUG] 'myFile'
[ERR] Could not read file myFile.
user@host ~/Desktop $

引用C11,第7.24.5.7章

char *strstr(const char *s1, const char *s2);

strstr函数定位s1字符串中的第一个匹配项,由 字符串中指向的字符序列(不包括终止 null 字符) 由s2.

因此,传递给strstr的两个参数都必须是字符串。在您的情况下,

char needle[1] = ".";

不是字符串。您没有为空终止符留出空间。要么使用

  • char needle[2] = ".";,至少,或者,
  • char needle[ ] = ".";,或者,
  • char const* needle = ".";

作为副作用,每当达到removeFileExtension()调用时,您都会面临未定义的行为

也就是说,当心!!

你正在做类似的事情

retp = strstr(haystack,needle);
if (*retp == '.')

即,从strstr()中取消引用返回的指针。如果strstr()返回 NULL 指针,您将再次陷入 UB 中。


编辑:

对于那些仍然对字符串有困惑的人,请查看第 §7.1.1 章中的定义(强调我的)

字符串是以第一个 null结尾并包含第一个 null 的连续字符序列 字符。[...]

至少我发现了问题:
删除文件扩展名后,我仍然 尝试打开旧文件指针fp,这 给了我空指针。新文件指针 仅在if(fp == NULL){...}体内 存在于if-语句的作用域内。

所以我创建了一个test_pointer,它首先查看 该文件甚至存在,如果没有,他会删除扩展名。 比我再次尝试打开文件,这次是fp.

感谢大家的提示,尤其是 苏拉夫·戈什 为您的改进建议!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int removeFileExtension(char *haystack);
int main(int argc, char const *argv[])
{
char filename[64];
strcpy(filename, argv[1]);

//----------------------------------------------------------------------------
// CHECK INPUT VALIDITY
//
if (argc != 2)
{
printf("Usage: ./ass2 [file-name]n");
return 1;
}

//----------------------------------------------------------------------------
// CHECK FILE EXISTENSE
//
FILE *test_pointer = fopen(filename, "r");                             //FOPEN
if (test_pointer == NULL)   // if not found: remove extension
{
int ret_val = removeFileExtension(filename);
if (ret_val == -1)
{
printf("[ERR] Could not remove file extension.n");
return 3;
}
}

//----------------------------------------------------------------------------
// OPEN FILE (INITIAL)
//
FILE *fp = fopen(filename, "r");                                       //FOPEN
if (fp == NULL)   // if still doesn't work: error
{
printf("[ERR] Could not read file %s.n", filename);
return 3;
}

//----------------------------------------------------------------------------
// READ DATA (INITIAL)
//
int bufsize = 1024;
char *buffer = malloc(bufsize * sizeof(char));                        //MALLOC
if (!buffer)
{
printf("[ERR] Out of memory.n");
return 2;
}
fseek(fp, 0, SEEK_SET);
fread(buffer, bufsize, 1, fp);
fclose(fp);                                                           //FCLOSE
printf("[DEBUG] %sn", buffer);
free(buffer);                                                           //FREE
buffer = NULL;
return 0;
}

int removeFileExtension(char *haystack)
{
char needle[] = ".";
char *retp;   // return pointer
retp = strstr(haystack,needle);
if(!retp)     // to prevent UB
return -1;
if (*retp == '.')
{
while (*retp != '')
{
*retp++ = '';
}
printf("[DEBUG] %sn", haystack);
}
return 0;
}