如何从 .t​​xt 文件中读取已知数量的未知大小的字符串并将每一行存储在矩阵的一行中(在 C 中)?

2024-04-21

标题是不言自明的。我几乎可以肯定,最终结果不会是一个矩阵,因为每行都有不同数量的列,所以它更像是可变大小的数组的数组。按大小对片段进行排序(最大的在前)也很有趣。这是我到目前为止所尝试过的:

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, ..一切正常);

  • 声明一个变量来跟踪读取的行数,并为每行递增;

  • 将文件的每一行读入缓冲区(POSIXgetline工作得特别好,因为它本身会动态分配足够的存储来处理任何行长度——使您不必使用固定缓冲区进行读取,并且必须分配和累积部分行,直到到达行尾)

  • 为每一行分配存储空间,将该行复制到新存储空间,并将起始地址分配给下一个指针,strdup为您执行这两件事,但由于它会分配,请确保您验证它是否成功;

  • 当你的索引达到当前分配的指针数量时,realloc更多指针(通常通过将数字加倍,或将数字增加3/2-- 如果增加不是特别重要,则速率 -- 重要的是确保您始终有一个有效的指针来分配保存行的新内存块);和

  • 重复直到文件被完全读取。

重新分配内存时需要注意一些微妙之处。第一次从来没有realloc直接指向正在重新分配的指针,例如不要做:

mypointer = realloc (mypointer, current_size * 2);

if 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] : %s\n", i, lines[i]);
        free (lines[i]);            /* free memory for each line */
    }
    free (lines);                   /* free pointers */

    return 0;
}

检查一下,如果您还有其他问题,请告诉我。如果你没有getline or strdup如果可用,请告诉我,我很乐意进一步帮助实现提供其行为的实现。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何从 .t​​xt 文件中读取已知数量的未知大小的字符串并将每一行存储在矩阵的一行中(在 C 中)? 的相关文章

随机推荐