首页 > 解决方案 > 将 .dat 数据添加到 C 结构?

问题描述

所以我必须在 C 中快速做一件事情并且需要这样的指导,因为我通常不使用 C。

我有 City.dat 文件,其中包含一些数据(我将其简化为 StackOverflow):

Postal-Code | City 
32            San Diego

在我的 City.h 文件中,我为它创建了结构:

typedef struct{

    int postalCode;
    char cityName;
} City;


typedef struct {
    City **city;
} CityList;

我应该如何处理 City.c 中的迭代以从 city.dat 收集所有数据?显然,我需要一个 for 循环,但我想看一个如何从 dat 文件中读取数据并打印出收集到的城市的示例?

标签: cfile-io

解决方案


char cityName;

真的应该

char *cityName;

我们实际上可以在这里使用一个灵活的数组,但我们不会,因为您的真实结构可能有多个字符串。

收集循环很容易。

#define SPLIT 15

// Stupid helper function to read a single line no matter how long.
// Really should be in the standard library but isn't.
static int readline(FILE *h, char **buf, size_t *nbuf)
{
    if (!*buf) {
        *buf = malloc(128);
        nbuf = 128;
    }
    size_t offset = 0;
    do {
        if (offset + 1 >= *nbuf) {
            // Just keep growing the line buffer until we have enough room.
            size_t nbuf2 = *nbuf << 1;
            char *buf2 = realloc(*buf, nbuf2);
            if (!buf2) return -1;
            *buf = buf2;
            *nbuf = nbuf2;
        }
        if (!fgets(buf + offset, *nbuf - offset, h)) return -1;
        offset += strlen(buf + offset);
    } while (offset > 0 && buf[offset - 1] == '\n');
    return 0;
}

CityList readfile(const char *file);
{
    errno = 0; // Check errno for short read.
    FILE *f = fopen(file);
    if (!f) return NULL;
    char *buf = NULL;
    size_t nbuf = 0;
    City **cities = NULL;
    size_t ncities;
    size_t acities;
    if (readline(f, &buf, &nbuf)) return NULL; // get rid of header line
    acities = 4;
    ncities = 0;
    cities = malloc(acities * sizeof(City**));
    if (!cities) return NULL;
    cities[0] = NULL; // Mark list empty
    while (!readline(f, &buf, &nbuf)) {
        // get new city struct
        int n = strtol(buf);
        int len = strlen(buf);
        if (len > 0 && buf[len] == '\n') buf[len--] = 0; // Cut off trailing \n
        if (len + 1 > SPLIT) /* validity check */ {
            if (ncities + 1 == acities) {
                size_t ncities2 = ncities << 1;
                City **cities2 = realloc(ncities 2 * sizeof (City**));
                if (!cities2) break;
            }
            // Allocate the entire struct and its data all at once.
            char *citybuf = malloc(sizeof(City*) + sizeof(City) + len - SPLIT + 1);
            City **city = (City*)citybuf;
            // Slot all the stuff into the structure
            city[0] = citybuf + sizeof(City *);
            city[0]->postalCode = n; // Value saved from above.
            city[0]->cityName = citybuf + sizeof(City *) + sizeof(City);
            strcpy(city[0]->cityName, buf + SPLIT);
            // Add city to list
            cities[ncities] = city;
            cities[++ncities] = NULL; // Mark end of list
        }
    }
    free(buf);
    fclose(f);
    CityList l = { cities };
    return l
}

当你来释放这个;CityList 中的每个条目都需要被释放,直到您到达 terminating NULL。分配同时分配了子指针、结构和结构内容,因此每个城市只有一次free调用。

特别的兴趣点:缓冲区被提前解析成块。然后立即分配城市结构,因为我们可以查看结构元素并说出我们需要多少空间。如果在读入后不编辑记录本身,则这样做是惯用的,因为代码既短又快。我很生气试图弄清楚如何处理错误,只是说 readerrno确实有效,但有些人不喜欢 clears 的代码errno。在幸福的道路上,清理errno很好。只有在错误路径上才会导致问题。

我还没有运行此代码。它可能有错误。


推荐阅读