将 .dat 数据添加到 C 结构?
Adding .dat data to a C struct?
所以我必须快速了解 C 并需要指导,因为我通常不使用 C。
我有 City.dat 个文件,其中包含一些数据(我在 Whosebug 中对其进行了简化):
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 文件中读取数据并打印出收集的城市?
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 中的每个条目都需要被释放,直到您到达终止 NULL
。分配一次分配了子指针、结构和结构内容,因此每个城市只有一个 free
调用。
特殊兴趣点:缓冲区被提前解析为块。然后一次分配城市结构,因为我们可以查看结构元素并说出我们需要多少space。如果记录本身在读入后没有被编辑,那么这样做是惯用的,因为代码既短又快。我很生气试图弄清楚如何处理错误,只是说读 errno
确实有效,但有些人不喜欢清除 errno
的代码。在快乐的道路上,清除 errno
就可以了。只有在错误路径上才会导致问题。
我没有运行这个代码。它可能有错误。
所以我必须快速了解 C 并需要指导,因为我通常不使用 C。
我有 City.dat 个文件,其中包含一些数据(我在 Whosebug 中对其进行了简化):
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 文件中读取数据并打印出收集的城市?
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 中的每个条目都需要被释放,直到您到达终止 NULL
。分配一次分配了子指针、结构和结构内容,因此每个城市只有一个 free
调用。
特殊兴趣点:缓冲区被提前解析为块。然后一次分配城市结构,因为我们可以查看结构元素并说出我们需要多少space。如果记录本身在读入后没有被编辑,那么这样做是惯用的,因为代码既短又快。我很生气试图弄清楚如何处理错误,只是说读 errno
确实有效,但有些人不喜欢清除 errno
的代码。在快乐的道路上,清除 errno
就可以了。只有在错误路径上才会导致问题。
我没有运行这个代码。它可能有错误。