簡體   English   中英

如何創建結構體數組

[英]how to create array of 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()時程序就會崩潰。 誰能告訴我如何解決它或給我一個更好的方法,謝謝。

您不能將值掃描到未分配的空間,換句話說,您需要為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];
    ...

stringchartypedef嗎? 我認為您的意思是string currency; 由於string通常是char *的別名,因此在這種情況下,您也需要為此成員留出空間: currency = malloc(100);

最后,看一看為什么“ while(!feof(file))”總是錯誤的?

簡短的摘要中有太多錯誤,建議您閱讀一本好書。

使用動態內存糾正了代碼,該內存允許您為大量數據保留空間(請參閱@LuisColorado的另一個答案),並使用fgetssscanf而不是fscanf

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

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

int main(void)
{
    FILE *fp = fopen("test_data.txt", "r");
    /* Always check the result of fopen */
    if (fp == NULL) {
        perror("fopen");
        exit(EXIT_FAILURE);
    }

    Data *tmp;
    tmp = malloc(sizeof(*tmp) * 50);
    if (tmp == NULL) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }

    char buf[512];
    int i = 0;
    /* Check that you don't read more than 50 lines */
    while ((i < 50) && (fgets(buf, sizeof buf, fp))) {
        sscanf(buf, "%d%99s%99s%lf%lf%7d", &tmp[i].date, tmp[i].currency, tmp[i].exchange, &tmp[i].low, &tmp[i].high, &tmp[i].daily_cap);
        i++;
    }
    fclose(fp);
    /* Always clean what you use */
    free(tmp);
    return 0;
}

當然不能。 想想您正在創建一個1.0E6寄存器的數組,該寄存器的sizeof (Data) ,我猜它不少於32個(四個指針)和200個字節(不少於這個字節,因為您沒有給出string類型的定義)和這個在64位元組的機器中(至少32位元組是216MBytes)是232MBytes(至少),而且如果類型string只有一個字元寬度(我怕不是),如果字串是char *的typedef,那么您就有432結構中的指針一個變量中給出432MBytes。 接下來,如果您將這個絕對巨大的變量聲明為局部變量,則必須知道大多數unix操作系統中的te堆棧限制在8Mb左右,這意味着您需要使用特殊參數構建程序以允許更大的堆棧最大值。尺寸。 而且,您可能還需要將帳戶增加到該大小,並使用ulimit來制作內核,以允許您使用如此大的堆棧大小段。

下次,請給我們完整的信息 ,因為不知道string類型的定義,或者發布的程序不完整,只會使我們猜測可能正在進行的事情,而無法發現實際錯誤。 這使您浪費時間,對我們來說也一樣。 謝謝。

如果您事先知道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數組(或為它們分配,具體取決於數字)。 以下是用於示例目的的簡單自動存儲陣列。 例如

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

由於您正在讀取數據的“行”,因此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 ,設置一個標志以指示正在使用的存儲並繼續運行...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM