【问题标题】:Opening a file with path in malloc在 malloc 中打开带有路径的文件
【发布时间】:2009-11-19 21:45:48
【问题描述】:

我正在尝试使用 fopen 打开一个文件,但我不想要一个静态位置,因此我在用户运行程序时从用户那里获取字符串。 但是,如果用户不输入一个默认文件。

我可以将 malloc var 放入 fopen 路径参数中吗?

char *file_path_mem = malloc(sizeof(char));
if (file_path_mem != NULL) //Null if out of memory
{
  printf("Enter path to file, if in current directory then specify name\n");
  printf("File(default: marks.txt): ");

  while ((c = (char)getchar()) != '\n')
  {
    file_path_mem[i++] = c;
    file_path_mem = realloc(file_path_mem, i+1 * sizeof(char));
  }
    file_path_mem[i] = '\0';
    if (i == 0 && c == '\n')
    {
      file_path_mem = realloc(file_path_mem, 10 * sizeof(char);
      file_path_mem = "marks.txt";
    }
  }
  else
  {
    printf("Error: Your system is out of memory, please correct this");
    return 0;
  }
  if (i==0)
  {
    FILE *marks_file = fopen("marks.txt", "r");
  }
  else
  {
    FILE *marks_file = fopen(file_path_mem, "r");
  }
  free(file_path_mem);

你可能已经猜到我是一个 c 新手,所以如果我做错了什么可怕的事情,那么抱歉。

【问题讨论】:

    标签: c malloc fopen


    【解决方案1】:

    这不是你想的那样:

    file_path_mem = realloc(file_path_mem, 10 * sizeof(char);
    file_path_mem = "marks.txt";
    

    您要做的是更改第二行以将默认名称复制到分配的缓冲区中:

    strcpy(file_path_mem, "marks.txt");
    

    【讨论】:

      【解决方案2】:

      您可以将从 malloc 返回的 char* 直接传递给 fopen。只要确保它包含有效数据。尽管请确保您按照 R Samuel 指出的那样输入新字符串。

      顺便说一句,您对 realloc 的使用会带来非常糟糕的性能。 Realloc 的工作原理是查看是否有足够的空间来增长内存(这不是保证,realloc 必须只返回一个包含旧数据的 newSize 块)。如果没有足够的空间,它会分配一个新大小的新块,并将旧数据复制到新块。显然这是次优的。

      您最好分配一个块,例如 16 个字符,然后,如果您需要超过 16 个字符,则重新分配另外 16 个字符。会有一些内存浪费,但您可能不会复制任何类似内存的东西。

      编辑:除此之外。对于包含 7 个字符的字符串。使用 realloc 每个字节方案,您将生成以下过程。

      分配 1 个字节
      分配 2 个字节
      复制 1 个字节
      免费 1 个字节
      分配 3 个字节
      复制 2 个字节
      免费 2 个字节
      分配 4 个字节
      复制 3 个字节
      免费 3 个字节
      分配 5 个字节
      复制 4 个字节
      免费 4 个字节
      分配 6 个字节
      复制 5 个字节
      免费 5 个字节
      分配 7 个字节
      复制 6 个字节
      免费 6 个字节
      分配 8 个字节
      复制 7 个字节

      这是 8 次分配、7 次释放和 28 字节的副本。更不用说分配给数组的 8 个字节(7 个字符 + 1 个空终止符)。

      分配很慢。免费是缓慢的。复制比不复制慢很多。

      对于此示例,使用我一次分配 16 个字节的系统,您分配一次,分配 8 个字节。没有副本,唯一的免费是当你完成它时。你确实浪费了 8 个字节。但是......好吧...... 8个字节在宏伟的计划中算不了什么......

      【讨论】:

      • “分配很慢。”没错,但 I/O 也是如此。
      【解决方案3】:

      realloc 比循环的其余部分相对昂贵,因此您不妨从 128 字节缓冲区开始,如果填满,再重新分配 128 字节。

      我建议以下一些更改:

      在文件顶部定义您的默认位置

      char* defaultLocation = 'myfile.txt';
      char* locationToUse;
      

      在您的代码中使用常量而不是硬编码数字(例如您在其中的 10 个)

      int DEFAULT_INPUT_BUFFER_SIZE = 128;
      char* userInputBuffer = malloc(sizeof(char) * DEFAULT_INPUT_BUFFER_SIZE) );
      int bufferFillIndex = 0;
      

      仅不经常重新分配,如果可能则根本不重新分配(大小 128 缓冲区)

      while ((c = (char)getchar()) != '\n')
        {
          file_path_mem[bufferFillIndex++] = c;
          if (bufferFillIndex % DEFAULT_INPUT_BUFFER_SIZE == 0)
          {
              realloc(file_path_mem, (bufferFillIndex + DEFAULT_INPUT_BUFFER_SIZE) * sizeof(char);
          }
        }
      

      【讨论】:

        【解决方案4】:

        这里应该不是问题,但是对于重新定位,您应该像这样声明新尺寸

        file_path_mem = realloc(file_path_mem, (i+1) * sizeof(char));

        【讨论】:

          【解决方案5】:

          假设它在您的系统上可用,您可以使用 getline() 大大简化此操作:

          printf("Enter path to file, if in current directory then specify name\n");
          printf("File(default: marks.txt): ");
          
          int bufSize = 100;
          char* fileNameBuf = (char*) malloc(bufSize + 1);
          int fileNameLength = getline(&fileNameBuf, &bufSize, stdin);
          
          if(fileNameLength < 0)
          {
              fprintf(stderr, "Error: Not enough memory.\n")
              exit(1);
          }
          
          /* strip line end and trailing whitespace. */
          while(fileNameLength && fileNameBuf[fileNameLength - 1] <= ' ')
              --fileNameLength;
          fileNameBuf[fileNameLength] = 0;
          
          if(!fileNameLength)
          {
              free(fileNameBuf); /* Nothing entered; use default. */
              fileNameBuf = "marks.txt";
          }
          
          FILE *marks_file = fopen(fileNameBuf, "r");
          
          if(fileNameLength)
              free(fileNameBuf);
          

          我不知道你的 C 是否支持块内声明,所以如果需要,我会让你解决这个问题。

          编辑:这是getline tutorial.

          【讨论】:

            【解决方案6】:

            作为一种学习经验,我会赞同其他人的建议,将您的缓冲区扩大一个字节以上。如果它不在循环中,则不会有任何区别,但在其他上下文中对每个字节调用 realloc() 是不可接受的。

            一个相当有效的技巧是每次缓冲区填满时将其大小加倍。

            另一方面,如果你真的只是想打开一个文件而不关心编写世界上最伟大的名称循环,那么标准程序就是简化代码,即使以限制文件名长度为代价。没有规定必须接受愚蠢的路径名。

            FILE *read_and_open(void)
            {
              char *s, space[1000];
            
              printf("Enter path to file, if in current directory then specify name\n");
              printf("File(default: marks.txt): ");
            
              fgets(space, sizeof space, stdin);
              if((s = strchr(space, '\n')) != NULL)
                *s = 0;
              if (strlen(space) == 0)
                return fopen("marks.txt", "r");
              return fopen(space, "r");
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-04-30
              • 1970-01-01
              • 1970-01-01
              • 2020-09-15
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多