从C中的文件中读取一行,动态地
#include #include int main() { FILE *input_f; input_f = fopen("Input.txt", "r"); //Opens the file in read mode. if (input_f != NULL) { char line[2048]; while( fgets(line, sizeof line, input_f) != NULL ) { //do something } fclose(input_f); //Close the input file. } else { perror("File couldn't opened"); //Will print that file couldn't opened and why. } return 0; }
你好。 我知道我可以在C中逐行读取这段代码,但我不想限制行大小,比如2048这段代码。
我想过使用malloc,但是在我阅读它之前我不知道线的大小,所以IMO无法完成。
有没有办法不限制线尺寸?
这个问题只是为了我的好奇心,谢谢。
在动态分配内存时,您需要更改:
char line[2048];
至
#define MAXL 2048 /* the use of a define will become apparent when you */ size_t maxl = MAXL; /* need to check to determine if a realloc is needed */ char *line = malloc (maxl * sizeof *line); if (!line) /* always check to insure allocation succeeded */ ...error.. memory allocation failed
你读取读取( maxl -1
)字符或newline
(如果使用fgetc
等等)或读取行,然后检查line [strlen (line) - 1] == '\n'
以确定是否读取整行(如果使用fgets
)。 (POSIX要求所有行以newline
终止)如果您读取maxl
字符( fgetc
)或未读取换行符( fgets
),则它是一个简短的读取,并且剩余更多字符。 您的选择是重新分配(通常将大小加倍)并再试一次。 重新分配:
char *tmp = realloc (line, 2 * maxl) if (tmp) { line = tmp; maxl *= 2; }
注意: 永远不要使用原始指针重新分配(例如line = realloc (line, 2 * maxl)
因为如果realloc
失败,则释放内存并将指针设置为NULL
并且您将丢失line
中存在的任何数据。还要注意maxl
每次重新分配时,通常会加倍。但是,您可以自由选择您喜欢的任何大小增加方案。(如果您担心将所有分配的新内存归零,可以使用memset将新分配的空间初始化为零/ null。在某些情况下,您要确保您的line
始终以null-terminated
)
这是基本的动态分配/重新分配方案。 请注意,在阅读完整的行之前,您正在阅读,因此您需要重新构建循环测试。 最后,由于您分配了内存,因此您负责在完成内存后释放内存。 一个你不能没有的工具是valgrind
(或类似的内存检查器)来确认你没有泄漏内存。
提示如果您正在阅读并希望确保您的字符串始终以null-terminated
,那么在分配您的内存块后,将所有字符归零( 0
)。 如前所述, memset
是可用的,但是如果选择calloc
而不是malloc
,它将为您调整内存。 但是,在重新分配时,新空间不会以任何方式置零,因此无论最初分配块的function如何,都需要调用memset
。
提示2查看POSIX getline
。 只要将line
初始化为NULL
getline
就会处理所需的分配/重新分配。 getline
还返回实际读取的字符数,需要在fgets
确定后调用strlen
。
如果您还有其他问题,请与我们联系。
考虑两个想法:
-
分配的内存的上限是合理的。 任务的性质应该对最大行长度有所了解,无论是80,1024还是1 MB。
-
使用智能操作系统,在需要之前可能不会实际使用已分配的内存。 请参阅为什么malloc没有“耗尽”我计算机上的内存?
因此,让代码分配1个大缓冲区来限制病态情况,让底层内存管理(重新)根据需要分配实内存。
#define N (1000000) char *buf = malloc(N); ... while (fgets(buf, N, stdin) != NULL)) { size_t len = strlen(buf); if (len == N-1) { perror("Excessive Long Line"); exit(EXIT_FAILURE); } } free(buf);