从文件中读取并在动态结构

时间:2016-08-14 15:41:33

标签: c file memory-management struct binary

我试图解决这个问题:

  

创建文件stringhe.h stringhe.c,让您使用以下结构和功能"

struct stringa {
    unsigned char length;
    char *s;
};

struct stringa *read_stringhe_bin(const char *filename, unsigned int *pn);
  

该结构包含length字段,其中包含字符串(可能为0)和s字段的长度,该字段指向以零结尾的字符串(长度为length)。该函数将一个文件名作为参数,该文件名将以未翻译的读取模式打开(二进制),并指向一个unsigned int变量的指针,您必须在该变量中输入文件中的字符串数。

     

该文件由一系列长度元素组成   一个变量,其中一个字节表示字符串的长度n,下面有n字节,包含字符串的字符。

     

该函数必须返回指向新内存区域的指针(动态分配)   heap)包含从文件中读取的所有字符串。字符串的数量不是先验的,不受限制。

     

它可以受代码约束。即使s字符串元素也必须动态分配堆。

这是我的代码:

stringhe.h

#include <stdio.h>
#include <stdlib.h>

struct stringa {
    unsigned char length;
    char *s;
};

#ifndef READ
#define READ
struct stringa *read_stringhe_bin(const char *filename, unsigned int *pn);
#endif // !READ

stringhe.c

#include "stringhe.h"

struct stringa *read_stringhe_bin(const char *filename, unsigned int *pn) {
    FILE *f;
    f = fopen(filename, "r+b");
    if (f == NULL) exit(1);

    struct stringa *lista;
    lista = malloc(0);
    lista->s = malloc(0);

    for (int i = 0; ; i++) {
        char a;

        fseek(f, 1, SEEK_CUR);
        if (fgetc(f) == EOF) break;

        fseek(f, -2, SEEK_CUR);
        fread(&a, 1, 1, f);

        lista = (struct stringa *)realloc (lista, sizeof(struct stringa) * (size_t)(i + 1));
        lista[i].length = a;
        lista[i].s = malloc(sizeof(char) * (size_t)a);

        fread(lista[i].s, 1, (size_t)a, f);
        lista[i].s[a] = '\0';
        (*pn)++;
    }

    fclose(f);

    return lista;
}

我将以下二进制文件传递给函数:

05 43 69 61 6F 21 00 03 61 62 63 0E 50 72 6F 67
72 61 6D 6D 61 7A 69 6F 6E 65

被翻译成:

.Ciao!..abc.Prog
rammazione

所以...通过调试我的功能似乎完美无缺,但是当我将它上传到我们教授的网站上以确定它是否真的有效时,它会说main(由教授创建,和我看不到)结果不正确。 所以我怀疑我在内存分配或其他类似方面做错了。你能不能帮我理解错误,并可能改进我的代码以使其更强大?

1 个答案:

答案 0 :(得分:3)

您的代码存在多个问题:

您使用"r+b"模式打开文件。更新无用且容易出错,只需使用"rb"

如果无法打开文件,您可能只返回NULL而不是退出程序。

lista = malloc(0);
lista->s = malloc(0);

malloc(0)可能会返回NULL或您不应该写入的对象的地址。你应该这样做:

lista = NULL;

为字符串字符分配空间时:

lista[i].s = malloc(sizeof(char) * (size_t)a);

您应该从读取文件中的字节后为您设置的终止'\0'分配一个额外字节。这样做:

lista[i].s = malloc(a + 1);

寻求检查文件结尾很麻烦,实际上可能不受流支持。只需将大小的一个字节读入int,检查EOF,然后为内容分配和读取指定的字节数:

    int a;

    a = fgetc(f);
    if (a == EOF) break;

    lista = realloc(lista, sizeof(*lista) * (size_t)(i + 1));
    lista[i].length = a;
    lista[i].s = malloc(a + 1);
    lista[i].s[a] = '\0';

    if (fread(lista[i].s, 1, a, f) != a) {
        // file format error, ignore this incomplete string
        break;
    }

您还应检查mallocrealloc可能无法分配内存并正常返回NULL

最后,返回分配的字符串数的方式不正确:

(*pn)++;

进入您的函数时,您不知道*pn是否为0 ...它可能在main()中未初始化。通过在解析循环结束时设置一次来解决此问题:

*pn = i;

另外,为什么要在stringe.h中使用#ifndef READ包围您的功能声明等。保护的目的是什么?