首页 > 解决方案 > 将文件逐行读入C中的字符串数组

问题描述

我正在尝试将以下文件逐行读取到字符串数组中,其中每一行都是数组的一个元素:

AATGC
ATGCC
GCCGT
CGTAC
GTACG
TACGT
ACGTA
CGTAC
GTACG
TACGA
ACGAA

我的代码如下:

void **get_genome(char *filename) {
    FILE *file = fopen(filename, "r");
    int c;
    int line_count = 0;
    int line_length = 0;
    for (c = getc(file); c != EOF; c = getc(file)) {
        if (c == '\n') line_count++;
        else line_length++;
    }
    line_length /= line_count;
    rewind(file);

    char **genome = calloc(line_length * line_count, sizeof(char));
    for (int i = 0; i < line_count; i++) {
        genome[i] = calloc(line_length, sizeof(char));
        fscanf(file, "%s\n", genome[i]);
    }

    printf("%d lines of %d length\n", line_count, line_length);

    for (int i = 0; i < line_count; i++)
        printf("%s\n", genome[i]);
}

但是,由于某种原因,我得到了数组前 2 个元素的垃圾输出。以下是我的输出:

`NP��
�NP��
GCCGT
CGTAC
GTACG
TACGT
ACGTA
CGTAC
GTACG
TACGA
ACGAA

标签: arrayscstringfile-io

解决方案


您似乎假设所有行都具有相同的行长。如果是这样的话,你仍然有一些问题:

  • 行指针的内存分配不正确,应该是

      char **genome = calloc(line_count, sizeof(char *));
    

或者更好,更不容易出错:

    char **genome = calloc(line_count, sizeof(*genome));
  • 每行的内存应该比空终止符长一个字节。

  • \nfscanf()格式字符串匹配任何空白字符序列。%s无论如何跳过这些都是多余的。

  • 如果文件包含任何空白字符,则对以空格分隔的项目进行计数会更安全,以避免对项目进行错误计数。

  • 你不关闭file

  • 你不要genome在函数的末尾返回

  • 你不检查错误。

这是修改后的版本:

void **get_genome(const char *filename) {
    FILE *file = fopen(filename, "r");
    if (file == NULL)
        return NULL;
    int line_count = 1;
    int item_count = 0;
    int item_length = -1;
    int length = 0;
    int c;
    while ((c = getc(file)) != EOF) {
        if (isspace(c)) {
            if (length == 0)
                continue;  // ignore subsequent whitespace
            item_count++;
            if (item_length < 0) {
                item_length = length;
            } else
            if (item_length != length) {
                printf("inconsistent item length on line %d\", line_count);
                fclose(file);
                return NULL;
            }
            length = 0;
        } else {   
            length++;
        }
    }
    if (length) {
        printf("line %d truncated\n", line_count);
        fclose(file);
        return NULL;
    }
    rewind(file);

    char **genome = calloc(item_count, sizeof(*genome));
    if (genome == NULL) {
        printf("out of memory\n");
        fclose(file);
        return NULL;
    }
    for (int i = 0; i < item_count; i++) {
        genome[i] = calloc(item_length + 1, sizeof(*genome[i]));
        if (genome[i] == NULL) {
            while (i > 0) {
                free(genome[i]);
            }
            free(genome);
            printf("out of memory\n");
            fclose(file);
            return NULL;
        }
        fscanf(file, "%s", genome[i]);
    }
    fclose(file);

    printf("%d items of %d length on %d lines\n",
           item_count, item_length, line_count);

    for (int i = 0; i < item_count; i++)
        printf("%s\n", genome[i]);

    return genome;
}

推荐阅读