如何创建struct数组

时间:2018-04-02 07:00:13

标签: c arrays pointers struct

我想实现一个搜索表和 这是数据:

20130610    Diamond CoinMate    11.7246 15.7762 2897
20130412    Diamond Bithumb     0.209   0.2293  6128
20130610    OKCash  Bithumb     0.183   0.2345  2096
20130412    Ethereum    Chbtc   331.7282    401.486 136786
20170610    OKCash  Tidex       0.0459  0.0519  66
...

和我的代码

typedef struct data{
    int *date;
    string currency[100];
    string exchange[100];
    double *low;
    double *high;
    int *daily_cap;
} Data;

int main()
{
    FILE *fp = fopen("test_data.txt", "r");
    Data tmp[50];
    int i = 0;
    while (!feof(fp)){
        fscanf(fp, "%d%s%s%f%f%7d", &tmp[i].date, tmp[i].currency, tmp[i].exchange, &tmp[i].low, &tmp[i].high, &tmp[i].daily_cap);
        i++;
    }
    fclose(fp);
}

但第一个问题是我无法创建一个大型数组来存储我的结构,如

Data tmp[1000000]

甚至我只尝试了50个元素,程序在完成main()时会崩溃。 任何人都可以告诉我如何解决它或给我一个更好的方法,谢谢。

3 个答案:

答案 0 :(得分:3)

您无法将值扫描到未分配的空间,换句话说,您需要为struct中的所有指针留出空间,切换到

typedef struct data{
    int date;
    string currency[100];
    string exchange[100];
    double low;
    double high;
    int daily_cap;
} Data;

或者在使用之前使用malloc为这些指针分配空间。

while (!feof(fp)){
   tmp[i].date = malloc(sizeof(int));
   ...

但在这种情况下,您不需要将此类成员的地址传递给fscanf,因为它们已经是指针:

fscanf(fp, "%d%s%s%f%f%7d", &tmp[i].date, ..

应该是

fscanf(fp, "%d%s%s%lf%lf%7d", tmp[i].date, ...

请注意,double需要%lf而不是%f

这也很令人困惑:

typedef struct data{
    int *date;
    string currency[100];
    ...

stringtypedef的{​​{1}}吗?我认为您的意思是char,因为string currency;通常是string的别名,在这种情况下,您也需要为此成员留出空间:char *

最后,看看Why is “while ( !feof (file) )” always wrong?

简短的片段中有太多错误,我建议你阅读一本好的C书。

使用动态内存纠正您的代码,允许您为大量数据预留空间(请参阅@LuisColorado的其他答案)并使用currency = malloc(100);fgets代替sscanf

fscanf

答案 1 :(得分:2)

当然你不能。认为你正在创建一个sizeof (Data)的1.0E6寄存器数组,我猜这个寄存器不小于32(四个指针)和200个字节(不小于这个,因为你没有给出类型{{1}的定义这是64字节机器中的232MBytes(至少)(在32位,它是216MBytes),如果类型string只有一个字符宽(我担心的不是),如果字符串是一个string的typedef然后你的结构中有432个指针,只有一个变量给出432MBytes。接下来,如果您将这个绝对巨大的变量声明为局部变量,您必须知道大多数unix操作系统中的te堆栈限制在大约8Mb,这意味着您需要使用特殊参数构建程序以允许更大的堆栈尺寸。而且你可能还需要你的帐户提高到这个大小的ulimits,以使内核允许你这么大的堆栈大小段。

请下次给我们full information,因为不知道char *类型的定义,或发布不完整的程序,只允许我们猜测可能正在进行的事情,而不是能够发现实际错误。这会让你浪费你的时间,对我们来说也是如此。感谢。

答案 2 :(得分:2)

如果您事先知道currencyexchange的列表,则无需在struct内分配或存储任何数组。列表可以是指向字符串文字的指针的全局数组,您需要做的就是存储指向currencyexchange的文字的指针(您甚至可以节省一些通过存储索引而不是指针来获取更多字节。

例如,您的交换列表可以存储一次,如下所示:

const char *currency[] = { "Diamond", "OKCash", "Ethereum" },
           *exchange[] = { "CoinMate", "Bithumb", "Chbtc", "Tidex" };

(如果数字有保证,请为字符串分配存储空间并从文件中读取)

现在您已经存储了currencyexchange的所有可能字符串,您在data结构中所需的只是每个字符串的指针,例如

 typedef struct {
    const char *currency, *exchange;
    double low, high;
    unsigned date, daily_cap;
} data_t;

unsigned提供更好的范围且没有否定datesdaily_cap

现在只需声明一个data_t数组(或为它们分配,具体取决于数字)。以下是一个简单的自动存储阵列,用于示例目的。 E.g。

#define MAXD 128
...
    data_t data[MAXD] = {{ .currency = NULL }};

因为你正在阅读' line'数据,fgets或POSIX getline是面向行的选择。读取一行后,您可以使用临时值解析sscanf行,比较从文件中读取的currencyexchange的值是否与存储的值匹配,然后指定一个指针结构的相应字符串,例如

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,设置一个标志以指示正在使用的存储并继续...