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

时间:2018-06-09 20:36:52

标签: c arrays malloc fgets fseek

标题非常自我解释。我几乎可以肯定,最终结果不是矩阵,因为每条线都会有不同数量的collums,所以它更像是一个可变大小的数组。按大小排序片段也是有趣的,最大的是。这是我到目前为止所尝试的:

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;
}

1 个答案:

答案 0 :(得分:0)

从C文件中读取未知数量的行到C中的内存是基本必需品。有几种方法可以解决它,但标准做法是:

  • 为文件中的行声明pointer to pointer to typechar**),以便在读入内存后收集和引用每一行;

  • 分配一些合理预期的指针数量,以避免重复调用realloc分别为每一行分配指针(最初分配8, 16, 32, ..所有工作正常);

    < / LI>
  • 声明一个变量来跟踪读取的行数,并为每一行增加;

  • 将文件的每一行读入缓冲区(POSIX getline特别有效,因为它本身将动态分配足够的存储空间来处理任何行长度 - 使您无需使用固定缓冲区读取并拥有分配和累积部分行直到到达行的末尾)

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

  • 当您的索引达到当前分配的指针数量时,realloc更多指针(通常是通过将数字加倍,或者将数字增加3/2) - 如果增加的数量不是{39} ; t特别重要 - 重要的是确保你总是有一个有效的指针来指定你的线路的新内存块);以及

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

重新分配内存时需要注意一些细微之处。首先永远不会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] : %s\n", i, lines[i]);
        free (lines[i]);            /* free memory for each line */
    }
    free (lines);                   /* free pointers */

    return 0;
}

仔细看看,如果您有其他问题,请告诉我。如果您没有getlinestrdup,请与我们联系,我很乐意帮助您进一步提供可以提供行为的实施方案。