我编写了一些代码,在内存使用方面尽可能保守,因此它会使用
realloc()
一次构建一个字符的字符串,而不是像常见的那样使用一次性固定长度缓冲区。我认为这样做的好处是,在重要的环境中,您永远不会过度使用内存,并且您不必担心缓冲区对于极端情况来说太小,也不必编写一些realloc()
代码来覆盖它。 我的问题是这是否会严重破坏内存或可能导致任何其他问题,或者编译器是否会优化它。
这是一个示例程序,它不使用固定长度的缓冲区来读取文本文件,并且运行良好。你为什么会或不会编写这样的代码?这显然是一个坏主意吗?
// Compile with: gcc a.c -o a
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]) {
void *tmp;
char **array = NULL; // array of line strings
size_t len = 0; // length of a line
int i = 0; // line count
// Open file
FILE* f;
if (!(f = fopen("./test.txt", "r"))) {
printf("Err: open file\n");
return 1;
}
// Read file into memory
char chr;
while ((chr = fgetc(f)) != EOF) {
// Reserve mem for another line
if (len == 0) {
// add 2 -- 1 for null terminator, 1 cuz i starts at 0
if ((tmp = realloc(array, (i+2)*sizeof(*array))) == NULL) {
printf("Err: realloc\n");
return 1;
}
array = tmp;
array[i] = NULL;
array[i+1] = NULL;
}
// Increase mem for next char in the line
// add 2 -- 1 for null terminator, 1 cuz len starts at 0
// Q: Why is best practice to omit sizeof knowing that for char it is always 1... all other alloc's need to use sizeof so the inconsistency leads to mistakes
if ((tmp = realloc(array[i], (len+2)*sizeof(*(array[i])))) == NULL) {
// if ((tmp = realloc(array[i], len+2)) == NULL) {
printf("Err: realloc\n");
return 1;
}
array[i] = tmp;
array[i][len] = chr;
array[i][len+1] = '\0';
len++;
// newline
if (chr == '\n') {
len = 0;
i++;
}
}
if (ferror(f)) {
printf("Err: read file\n");
return 1;
}
// Verify input
printf("\nRead:\n-----\n");
for (i=0; array[i] != NULL; i++) { // array is NULL terminated
printf("[%d] %s", i+1, array[i]);
free(array[i]);
}
free(array);
printf("\nDone\n");
fclose(f);
return 0;
}
当你第一次调用
malloc()
或realloc()
时,他会分配一大块内存。这是为了将来的调用,而不是在每次使用时都要求更多的内存。
realloc()
在一切之前,先看看分配的块后面,看看他是否可以用一些可用空间来扩展该块。如果他不能,他会为您malloc()
提供一个新的记忆空间。
这是一个很好的策略,但在你的情况下效果不太好。
这里的问题是你
realloc()
多个指针,所以你的内存看起来一团糟,你只是创建了一些碎片。
另一件事,现在的内存真的很便宜,你可以分配更多。 与 C++ 容器实现相比,它们分配了所需的空间 * 2,以提高性能。 您会因所有
realloc()
电话而浪费很多时间。