我正在努力从文件中获取文本行并将它们存储到数组中。我在我的代码上使用了一个调试器,它似乎得到了前几行文本,但当它到达第三行文本时,有一个分割错误。我认为我的allocate_mem()函数有问题,因为在read_lines()中的while循环的第三次迭代期间调用它时会发生错误。帮助将非常感激!
我代码:
#include <stdio.h>
#include <stdlib.h>
char* read_one_line(FILE* fp, char* line);
char* allocate_mem(FILE* fp, char* line);
void print_lines(char** lines, int num_lines){
int i;
for(i = 0 ; i < num_lines; ++i){
printf("%d. %s", i+1, lines[i]);
}
}
void free_lines(char** lines, int num_lines){
int i;
for(i = 0 ; i < num_lines; ++i){
free(lines[i]);
}
if(lines != NULL && num_lines > 0){
free(lines);
}
}
FILE* validate_input(int argc, char* argv[]){
FILE* fp = NULL;
if(argc < 2){
printf("Not enough arguments entered.nEnding program.n");
exit(0);
}
else if(argc > 2){
printf("Too many arguments entered.nEnding program.n");
exit(0);
}
fp = fopen(argv[1], "r");
if(fp == NULL){
printf("Unable to open file: %snEnding program.n", argv[1]);
exit(0);
}
return fp;
}
void read_lines(FILE* fp, char*** lines, int* num_lines) {
*num_lines = 0;
do {
*num_lines += 1;
*lines = realloc((*lines), (*num_lines) * sizeof(*lines));
(*lines)[*num_lines - 1] = read_one_line(fp, (*lines)[*num_lines - 1]);
} while((*lines)[*num_lines - 1] != NULL);
free((*lines)[*num_lines - 1]);
*num_lines -= 1;
}
char* read_one_line(FILE* fp, char* line) {
line = NULL;
int str_len = 0;
while (1) {
// resize buffer to hold next char, or zero termination
char *tmp = realloc(line, str_len + 1);
if (!tmp) {
free(line);
return NULL;
}
line = tmp;
// Get next character from file
int ch = fgetc(fp);
if (ch == EOF) {
free(line);
return NULL;
}
else if (ch == 'n') {
line[str_len] = 'n';
line[str_len + 1] = 0;
return line;
}
else {
line[str_len] = ch;
str_len++;
}
}
}
int main(int argc, char* argv[]){
char** lines = NULL;
int num_lines = 0;
FILE* fp = validate_input(argc, argv);
read_lines(fp, &lines, &num_lines);
print_lines(lines, num_lines);
free_lines(lines, num_lines);
fclose(fp);
return 0;
}
当为一行文本分配内存时,在读取该行之前,我们必须对ftell
、读取和丢弃、fseek
、内存分配和实际读取做一些神奇的操作。这并不难做到,但并不是所有的流都支持查找,我们必须考虑操作期间文件的更改。失败不能解释文件更改,可能是也可能不是安全问题。
最简单的方法是不是预先分配正确的大小,而是从一个小的字符串缓冲区开始,并在读取更多字符时调整缓冲区的大小。
/*
Read a line of text from `file` and store it in a freshly allocated
buffer
Return new string or NULL on error or premature EOF
*/
char *alloc_and_read_line(FILE *file)
{
char *str = NULL;
size_t str_len = 0
while (1)
{
/* resize buffer to hold next char, or zero termination */
char *tmp = realloc(str, str_len + 1);
if (!tmp)
{
free(str);
return NULL;
}
str = tmp;
/* Get next character from file */
int ch = fgetc(file);
if (ch == EOF)
{
/*
IO error in `file`, or last line was not correctly
terminated with newline
*/
free(str);
return NULL;
}
else if (ch == 'n')
{
/* End of line */
str[str_len] = 0;
return str;
}
else
{
str[str_len] = ch;
str_len++;
}
}
}
有些人喜欢以大于1的步长来调整缓冲区大小,或者在需要增长时将大小增加一倍。理论是,它应该更快,但它不是真正的现代realloc
实现的问题(我已经测量)。这只会增加更多的复杂性和出现bug的机会。
编辑:
关于您的新分割错误,*foo[bar]
与*(foo[bar])
相同,而不是(*foo)[bar]
。当涉及到运算符优先级时,编译器很乐意给出与您所希望的不同的意见。自由使用括号也无妨。