有很多方法可以解决这个问题。声明静态2D数组或char(例如。
char lines[40][50] = {{""}};
)或声明
指向char[50]类型数组的指针
,这可能是最容易进行动态分配的。使用这种方法,您只需要一次分配。使用常量
MAXL = 40
和
MAXC = 50
,您只需要:
char (*lines)[MAXC] = NULL;
...
lines = malloc (MAXL * sizeof *lines);
阅读每一行
fgets
是一项简单的任务:
while (i < MAXL && fgets (lines[i], MAXC, fp)) {...
当你完成后,你需要做的就是
free (lines);
把这些碎片放在一起,你可以这样做:
#include <stdio.h>
#include <stdlib.h>
enum { MAXL = 40, MAXC = 50 };
int main (int argc, char **argv) {
char (*lines)[MAXC] = NULL; /* pointer to array of type char [MAXC] */
int i, n = 0;
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* valdiate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
if (!(lines = malloc (MAXL * sizeof *lines))) { /* allocate MAXL arrays */
fprintf (stderr, "error: virtual memory exhausted 'lines'.\n");
return 1;
}
while (n < MAXL && fgets (lines[n], MAXC, fp)) { /* read each line */
char *p = lines[n]; /* assign pointer */
for (; *p && *p != '\n'; p++) {} /* find 1st '\n' */
*p = 0, n++; /* nul-termiante */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
/* print lines */
for (i = 0; i < n; i++) printf (" line[%2d] : '%s'\n", i + 1, lines[i]);
free (lines); /* free allocated memory */
return 0;
}
注意:
您还需要检查整行是否被
fgets公司
每次。(假设文件中有一行超过38个字符)。您可以通过检查
*p
是
'\n'
在使用
nul终止
性格(例如。
if (*p != '\n') { int c; while ((c = getchar()) != '\n' && c != EOF) {} }
). 确保下次阅读
fgets公司
将从下一行开始,而不是当前行中的剩余字符。
要包括支票,您可以执行以下类似操作(
注意:
我将读取循环计数器从
i
到
n
无需分配
n = i;
跟随读取循环)。
while (n < MAXL && fgets (lines[n], MAXC, fp)) { /* read each line */
char *p = lines[n]; /* assign pointer */
for (; *p && *p != '\n'; p++) {} /* find 1st '\n' */
if (*p != '\n') { /* check line read */
int c; /* discard remainder of line with getchar */
while ((c = fgetc (fp)) != '\n' && c != EOF) {}
}
*p = 0, n++; /* nul-termiante */
}
是否丢弃或保留超出数组长度的剩余行取决于您。然而,经常检查是一个好主意。(以下示例输入中的文本行数限制为17个字符,因此不可能有长行,但通常不能保证行长。
示例输入
$ cat dat/40lines.txt
line of text - 1
line of text - 2
line of text - 3
line of text - 4
line of text - 5
line of text - 6
...
line of text - 38
line of text - 39
line of text - 40
示例使用/输出
$ ./bin/fgets_ptr2array <dat/40lines.txt
line[ 1] : 'line of text - 1'
line[ 2] : 'line of text - 2'
line[ 3] : 'line of text - 3'
line[ 4] : 'line of text - 4'
line[ 5] : 'line of text - 5'
line[ 6] : 'line of text - 6'
...
line[38] : 'line of text - 38'
line[39] : 'line of text - 39'
line[40] : 'line of text - 40'
现在包括一个长度签入代码,并在输入中添加一个长行,例如:
$ cat dat/40lines+long.txt
line of text - 1
line of text - 2
line of text - 3 + 123456789 123456789 123456789 123456789 65->|
line of text - 4
...
重新运行该程序,您可以确认您现在已经保护了文件中的长行,从而妨碍了从文件中连续读取行。
动态重新分配
lines
如果文件中的行数未知,并且达到了初始分配
40
在里面
线
,那么您需要做的就是继续阅读其他行
realloc
存储
线
例如:
int i, n = 0, maxl = MAXL;
...
while (fgets (lines[n], MAXC, fp)) { /* read each line */
char *p = lines[n]; /* assign pointer */
for (; *p && *p != '\n'; p++) {} /* find 1st '\n' */
*p = 0; /* nul-termiante */
if (++n == maxl) { /* if limit reached, realloc lines */
void *tmp = realloc (lines, 2 * maxl * sizeof *lines);
if (!tmp) { /* validate realloc succeeded */
fprintf (stderr, "error: realloc - virtual memory exhausted.\n");
break; /* on failure, exit with existing data */
}
lines = tmp; /* assign reallocated block to lines */
maxl *= 2; /* update maxl to reflect new size */
}
}
现在,无论文件中有多少行,您只需继续重新分配
线
直到整个文件被读取,或者内存不足。(注意:当前代码为重新分配两倍的当前内存
线
每次重新分配时。您可以随意添加任意数量的内容。例如,您可以分配
maxl + 40
简单地分配
40
每次多行。
编辑以响应评论查询
如果您确实想使用固定数量的
线
您必须分配固定数量的额外
线
(增加次数
sizeof *lines
),您不能简单地添加
40
字节,例如。
void *tmp = realloc (lines, (maxl + 40) * sizeof *lines);
if (!tmp) { /* validate realloc succeeded */
fprintf (stderr, "error: realloc - virtual memory exhausted.\n");
break; /* on failure, exit with existing data */
}
lines = tmp; /* assign reallocated block to lines */
maxl += 40; /* update maxl to reflect new size */
}
回忆起
线
是一个
指向数组的指针
属于
char[50]
,因此对于要分配的每一行,必须为50个字符(例如。
*行大小
),因此固定增加40行将是
realloc (lines, (maxl + 40) * sizeof *lines);
,则必须准确更新已分配的最大行数(
maxl
)以反映
40
线路,例如。
maxl += 40;
.
示例输入
$ cat dat/80lines.txt
line of text - 1
line of text - 2
...
line of text - 79
line of text - 80
示例使用/输出
$ ./bin/fgets_ptr2array_realloc <dat/80lines.txt
line[ 1] : 'line of text - 1'
line[ 2] : 'line of text - 2'
...
line[79] : 'line of text - 79'
line[80] : 'line of text - 80'
仔细看看,如果你有任何问题,请告诉我。