在malloc中打开带路径的文件

时间:2009-11-19 21:45:48

标签: c malloc fopen

我正在尝试使用fopen打开一个文件,但我不想要一个静态位置,所以当他/她运行程序时我从用户那里获取字符串。 但是,如果用户未输入一个,则指定默认文件。

我可以将malloc var放入fopen path参数吗?

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);

你可能已经猜到我是新手,所以如果我做了一些可怕的错误,那就很抱歉。

6 个答案:

答案 0 :(得分:3)

这不符合您的想法:

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

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

strcpy(file_path_mem, "marks.txt");

答案 1 :(得分:3)

你可以将从malloc返回的char *直接传递给fopen。只需确保它包含有效数据。虽然如同Sam Samuel指出的那样,请确保你将新字符串括起来。

顺便说一句,你对realloc的使用会带来非常糟糕的表现。 Realloc通过查看是否存在增加内存的enogh空间来工作(这不是保证,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字节在宏观方案中没什么......

答案 2 :(得分:2)

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);
    }
  }

答案 3 :(得分:1)

这里不应该是一个问题,但对于重新定位,你应该说明新的大小

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

答案 4 :(得分:0)

您可以使用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.

答案 5 :(得分:0)

作为一种学习经验,我会根据其他人的建议,将缓冲区扩展一个以上的字节。如果它不在循环中但在每个字节上调用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");
}