如果您事先知道currency 和exchange 的列表,则无需在struct 中分配或存储任何数组。列表可以是指向 字符串文字 的全局指针数组,您需要做的就是为 currency 和 exchange 存储指向文字的指针(您甚至可以通过存储来节省更多字节索引而不是指针)。
例如,您的交易所列表可以按如下方式存储一次:
const char *currency[] = { "Diamond", "OKCash", "Ethereum" },
*exchange[] = { "CoinMate", "Bithumb", "Chbtc", "Tidex" };
(如果数量允许,为字符串分配存储空间并从文件中读取)
现在您已经存储了currency 和exchange 的所有可能字符串,您在data 结构中需要的只是每个字符串的指针,例如
typedef struct {
const char *currency, *exchange;
double low, high;
unsigned date, daily_cap;
} data_t;
(unsigned 给出了更好的范围,并且没有否定的dates 或daily_cap)
现在只需声明一个data_t 数组(或为它们分配,取决于数量)。下面是一个简单的自动存储数组,用于示例目的。例如
#define MAXD 128
...
data_t data[MAXD] = {{ .currency = NULL }};
由于您正在读取“行”数据,fgets 或 POSIX getline 是面向行的选择。读取一行后,您可以使用临时值解析带有sscanf 的行,比较从文件中读取的currency 和exchange 的值是否与存储的值匹配,然后将指向适当字符串的指针分配给您的结构,例如
int main (void) {
char buf[MAXC] = "";
size_t n = 0;
data_t data[MAXD] = {{ .currency = NULL }};
while (n < MAXD && fgets (buf, MAXC, stdin)) {
char curr[MAXE] = "", exch[MAXE] = "";
int havecurr = 0, haveexch = 0;
data_t tmp = { .currency = NULL };
if (sscanf (buf, "%u %31s %31s %lf %lf %u", &tmp.date,
curr, exch, &tmp.low, &tmp.high, &tmp.daily_cap) == 6) {
for (int i = 0; i < NELEM(currency); i++) {
if (strcmp (currency[i], curr) == 0) {
tmp.currency = currency[i];
havecurr = 1;
break;
}
}
for (int i = 0; i < NELEM(exchange); i++) {
if (strcmp (exchange[i], exch) == 0) {
tmp.exchange = exchange[i];
haveexch = 1;
break;
}
}
if (havecurr & haveexch)
data[n++] = tmp;
}
}
...
把它放在一个简短的例子中,你可以做类似以下的事情:
#include <stdio.h>
#include <string.h>
#define MAXC 256
#define MAXD 128
#define MAXE 32
#define NELEM(x) (int)(sizeof (x)/sizeof (*x))
const char *currency[] = { "Diamond", "OKCash", "Ethereum" },
*exchange[] = { "CoinMate", "Bithumb", "Chbtc", "Tidex" };
typedef struct {
const char *currency, *exchange;
double low, high;
unsigned date, daily_cap;
} data_t;
int main (void) {
char buf[MAXC] = "";
size_t n = 0;
data_t data[MAXD] = {{ .currency = NULL }};
while (n < MAXD && fgets (buf, MAXC, stdin)) {
char curr[MAXE] = "", exch[MAXE] = "";
int havecurr = 0, haveexch = 0;
data_t tmp = { .currency = NULL };
if (sscanf (buf, "%u %31s %31s %lf %lf %u", &tmp.date,
curr, exch, &tmp.low, &tmp.high, &tmp.daily_cap) == 6) {
for (int i = 0; i < NELEM(currency); i++) {
if (strcmp (currency[i], curr) == 0) {
tmp.currency = currency[i];
havecurr = 1;
break;
}
}
for (int i = 0; i < NELEM(exchange); i++) {
if (strcmp (exchange[i], exch) == 0) {
tmp.exchange = exchange[i];
haveexch = 1;
break;
}
}
if (havecurr & haveexch)
data[n++] = tmp;
}
}
for (size_t i = 0; i < n; i++)
printf ("%u %-10s %-10s %8.4f %8.4f %6u\n", data[i].date,
data[i].currency, data[i].exchange, data[i].low,
data[i].high, data[i].daily_cap);
}
使用/输出示例
$ ./bin/coinread <dat/coin.txt
20130610 Diamond CoinMate 11.7246 15.7762 2897
20130412 Diamond Bithumb 0.2090 0.2293 6128
20130610 OKCash Bithumb 0.1830 0.2345 2096
20130412 Ethereum Chbtc 331.7282 401.4860 136786
20170610 OKCash Tidex 0.0459 0.0519 66
使用这种方法,无论您是为结构数组分配还是使用自动存储,都可以通过不重复存储已知值来最小化存储数据的大小。在 x86_64 上,您的 data_t 结构大小约为 40 字节。平均而言,使用1-4 Megabyte 堆栈,您可以在需要开始分配之前安全地存储大量40-byte 结构。你总是可以从自动存储开始,如果你达到了可用堆栈空间的某个百分比,动态分配,memcpy,设置一个标志来指示正在使用的存储并继续......