由于行长度和文本文件行数均未知,相当于二维 char 数组的两维长度都未定义。由于 getline 函数可以自动扩充 char 数组长度,我最初的想法是使用 getline 得到每行,然后每次对 char ** 进行 realloc,直到读完整个文件。
但是这种做法并不好,首先 getline 是 glibc 的扩展,而不是 C 语言的标准函数,使用除 gcc 以外的编译器是不一定能编译通过的;其次,每次对 char ** 指针进行 realloc 显得代码很 ugly。可以使用 fgets 替代 getline,但是就要自己来控制一维 char 数组的长度。
后来想想,换了一种思路,首先将整个文件读入内存,然后根据 '\n' 的个数来计算文件的行数,作为二维数组的长度,然后将所有的 '\n' 替换成 '\0',并将每一行的指针赋给二维 char 数组,代码如下:
char ** text_2_array(const char *filename)
{
char *p, **array;
int lines;
if(filename == NULL) return NULL;FILE *fp = fopen(filename, "r");
if(fp == NULL) return NULL;/* Get file size. */
fseek(fp, 0L, SEEK_END);
long int f_size = ftell(fp);
fseek(fp, 0L, SEEK_SET);/* Allocate space for file content. */
char *buf = (char *) calloc(f_size, sizeof(char));
if(buf == NULL) return NULL;fread(buf, sizeof(char), f_size, fp);
fclose(fp);/* Get number of lines. */
for(p=strchr(buf, '\n'), lines=1; p!=NULL; p=strchr(p, '\n'), lines++) {
if(*p == '\n') p++;
}/* Allocate space for array; split file buffer to lines by change '\n' to
'\0'. */
array = (char **) calloc(lines+1, sizeof(char*));
array[0] = buf;
for(p=strchr(buf, '\n'), lines=1; p!=NULL; p=strchr(p, '\n')) {
if(*p == '\n') *p++ = '\0';
if(p != NULL) array[lines++] = p;
}
/* Add a terminate NULL pointer. */
array[lines] = NULL;
return array;
}
其实读文本文件入数组这个功能在很多语言中是很简单的操作,比如 PHP 的 file 函数,或者 Bash 的 (`cat filename`),都可以直接实现这个功能。但是对 C 这种更低级的语言来说,貌似就没那么简单了。我想要了解的是,除了我上面提到的两种思路,有没有更简单或者直接的方法来解决这个问题?比如一些我不熟悉的函数,或者一些 trick。