>标题是不言自明的。我几乎可以肯定最终结果不会是一个矩阵,因为每一行都有不同数量的列,所以它更像是一个可变大小的数组数组。按大小对片段进行排序也会很有趣,最大的是第一。这是我到目前为止尝试过的:
int main() {
char str[MAXLEN], **fragmentsList;
int number_of_strings, i, max, k;
printf("Enter .txt file name: ");
scanf("%s", str);
printf("How many strings does the file has? ");
scanf("%d", &number_of_strings);
FILE *arq;
arq = fopen(str, "r");
for (i = 0, max = 0; !feof(arq); i++) {
while (fscanf("%c") != 'n') {
max++;
}
if (max > k) {
k = max;
}
}
fclose(arq);
fragmentsList = malloc(k * sizeof(char));
*fragmentsList = malloc(number_of_strings * sizeof(char));
arq = fopen(str, "r");
for (i = 0; !feof(arq); i++) {
fscanf(arq, "%s", fragmentList[i]);
}
for (i = 0; i < number_of_strings; i++) {
printf("%s", fragmentList[i]);
}
return 0;
}
在 C 语言中将未知数量的行从文件中读取到内存中是基本必需的。有几种方法可以解决这个问题,但标准做法是:
-
声明一个
pointer to pointer to type
(文件中的行char**
(,以允许您在读入内存后收集和引用每一行; -
首先分配一些合理预期的指针数量,以避免重复调用
realloc
单独为每行分配指针(最初分配8, 16, 32, ..
一切正常(; -
声明一个变量来跟踪读取的行数,并递增每行;
-
将文件的每一行读入缓冲区(POSIX
getline
工作特别好,因为它本身将动态分配足够的存储空间来处理任何行长度 - 让您无需使用固定缓冲区读取,并且必须分配和累积部分行,直到到达行尾( -
为每一行分配存储,将行复制到新存储,并将开始地址分配给下一个指针,
strdup
为您执行这两项操作,但由于它会分配,请确保验证它是否成功; -
当你的索引达到你当前分配的指针数量时,
realloc
更多的指针(通常是通过加倍的数量,或者将数量增加3/2
- 如果增加不是特别重要,则速率 - 重要的是确保你始终有一个有效的指针来分配新的内存块来保存你的行(; -
重复上述步骤,直到文件完全读取。
重新分配内存时需要注意一些细微之处。首先,永远不要直接realloc
到被重新分配的指针,例如不要这样做:
mypointer = realloc (mypointer, current_size * 2);
如果realloc
失败,它将返回NULL
,如果将返回分配给原始指针,则会覆盖当前数据的地址,NULL
创建内存泄漏。相反,在将新内存块分配给原始指针之前,请始终使用临时指针并验证realloc
成功,例如
if (filled_pointers == allocated pointers) {
void *tmp = realloc (mypointer, current_size * 2);
if (tmp == NULL) {
perror ("realloc-mypointer");
break; /* or use goto to jump out of your read loop,
* preserving access to your current data in
* the original pointer.
*/
}
mypointer = tmp;
current_size *= 2;
}
使用getline
将这些部分完全放在示例中,您可以执行以下操作。(注意:代码期望文件名作为程序的第一个参数读取,如果没有给出参数,程序将默认从stdin
读取(
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NPTR 8 /* initial number of pointers (must be > 0) */
int main (int argc, char **argv) {
size_t ndx = 0, /* line index */
nptrs = NPTR, /* initial number of pointers */
n = 0; /* line alloc size (0, getline decides) */
ssize_t nchr = 0; /* return (no. of chars read by getline) */
char *line = NULL, /* buffer to read each line */
**lines = NULL; /* pointer to pointer to each line */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.n", argv[1]);
return 1;
}
/* allocate/validate initial 'nptrs' pointers */
if (!(lines = calloc (nptrs, sizeof *lines))) {
perror ("calloc - lines");
return 1;
}
/* read each line with POSIX getline */
while ((nchr = getline (&line, &n, fp)) != -1) {
if (nchr && line[nchr - 1] == 'n') /* check trailing 'n' */
line[--nchr] = 0; /* overwrite with nul-char */
char *buf = strdup (line); /* allocate/copy line */
if (!buf) { /* strdup allocates, so validate */
perror ("strdup-line");
break;
}
lines[ndx++] = buf; /* assign start address for buf to lines */
if (ndx == nptrs) { /* if pointer limit reached, realloc */
/* always realloc to temporary pointer, to validate success */
void *tmp = realloc (lines, sizeof *lines * nptrs * 2);
if (!tmp) { /* if realloc fails, bail with lines intact */
perror ("realloc - lines");
break; /* don't exit, lines holds current lines */
}
lines = tmp; /* assign reallocted block to lines */
/* zero all new memory (optional) */
memset (lines + nptrs, 0, nptrs * sizeof *lines);
nptrs *= 2; /* increment number of allocated pointers */
}
}
free (line); /* free memory allocated by getline */
if (fp != stdin) fclose (fp); /* close file if not stdin */
for (size_t i = 0; i < ndx; i++) {
printf ("line[%3zu] : %sn", i, lines[i]);
free (lines[i]); /* free memory for each line */
}
free (lines); /* free pointers */
return 0;
}
仔细查看,如果您有其他问题,请告诉我。如果您没有可用的getline
或strdup
,请告诉我,我很乐意进一步帮助提供其行为的实现。