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

Why does fopen() not recognize my file's name?

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

它确实通过将 stringtext 复制到 filename:

打开了我的文件
strcpy(filename,text);
FILE *fp = fopen(filename, "r");

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

为了检查它是否有效,我配对了一个名为 strComparison()function, 其中 returns 为 qual 时 0 或不相等时为 1。 问题是,删除文件扩展名后,它显示两个字符串 是合格的,但我仍然无法打开文件。

当我输入 ./a.out myFile.txt 我的比较 function returns 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_story[=11=]txt", "r");   // this way does work
  if (fp == NULL)
  {
    // IF NOT FOUND: REMOVE EXTENSION
    removeFileExtension(filename);
    char text[] = "myFile[=11=]";
    int ret_val = -1;
    ret_val = strComparison(filename, text);
    if (ret_val == 0)
      printf("[DEBUG] equal\n");
    else
      printf("[DEBUG] unequal\n");

    printf("[DEBUG] ret_val: %d\n", 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] %s\n", 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 != '[=11=]')
    {
      *retp++ = '[=11=]';
    }
    printf("[DEBUG] %s\n", 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 != '[=11=]') || (*two != '[=11=]') );
  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);

The strstr function locates the first occurrence in the string pointed to by s1 of the sequence of characters (excluding the terminating null character) in the string pointed to by s2.

因此,传递给 strstr 的两个参数都必须是 strings。在你的情况下,

 char needle[1] = ".";

不是 字符串 。您不允许 空终止符 使用 space。要么使用

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

作为副作用,每当到达对 removeFileExtension() 的调用时,您将面临 undefined behavior

也就是说,小心!!

你正在做类似的事情

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

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


编辑:

对于那些仍然对 string 感到困惑的人,请查看章节 §7.1.1 中的定义(强调我的

A string is a contiguous sequence of characters terminated by and including the first null character. [...]

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

所以我创建了一个 test_pointer,它首先看起来是否 该文件甚至存在,如果不存在,他将删除扩展名。 然后我再次尝试打开文件,这次是 fp.

感谢大家的提示,尤其是 Sourav Ghosh 征求您的改进建议!

#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] %s\n", 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 != '[=10=]')
    {
      *retp++ = '[=10=]';
    }
    printf("[DEBUG] %s\n", haystack);
  }
  return 0;
}