2009-11-19 63 views
0

我想用fopen打开一个文件,但我不想要一个静态位置,所以我在用户运行程序时从中获取字符串。 但是,如果用户没有输入,则指定默认文件。在malloc中打开一个带有路径的文件

我可以将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新手,所以如果我做了一些可怕的错误,那么对不起。

回答

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

这不是做你认为它是:

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

你想要做的是改变第二行的默认名称复制到分配的缓冲区什么:

strcpy(file_path_mem, "marks.txt"); 
3

你可以将从malloc返回的char *直接传入fopen。只要确保它包含有效的数据。正如R Samuel指出的那样,确保你能够使用新字符串。

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

你最好分配一个16字节的数据块,然后如果你需要16个以上的数据块,可以重新分配16个字节。会有一些内存浪费,但你不可能像任何内存一样拷贝任何东西。

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

的alloc 1字节
ALLOC 2字节
拷贝1字节
自由1字节
ALLOC 3字节
拷贝2字节
免费2字节
ALLOC 4字节
拷贝3字节
自由3字节
alloc 5字节
复制4字节
免费4字节
ALLOC 6字节
复制5个字节
自由5个字节
ALLOC 7字节
复制6个字节
自由6个字节
ALLOC 8字节
拷贝7字节

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

分配很慢。 Frees很慢。复制比不复制慢得多。

对于本例中使用我分配16个字节的时间系统分配一次,分配8个字节。没有副本,唯一免费的是当你完成它。尽管你浪费了8个字节。但是......好吧...... 8字节在事物的宏伟计划中没有任何意义......

+0

that和realloc可能会失败 – Bahbar 2009-11-19 22:00:48

+0

所以malloc可以介意。每次1步:) – Goz 2009-11-19 22:05:56

+0

“分配很慢”。诚然,I/O也是如此。 – 2009-11-19 22:16:09

1

不应该是一个问题在这里,但对于realocation你应说明这样的

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

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.

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"); 
} 
+0

嘿,我把一个bsd'ism,好点,我会解决它 – DigitalRoss 2009-11-19 22:33:19

相关问题