簡體   English   中英

C - 使用 strtok 的分段錯誤

[英]C - Segmentation fault using strtok

我有這段代碼,它讀取多個文件並打印某個值。 讀取文件后,在某個時刻我的 while 循環停止並顯示分段錯誤...

這是我的代碼

int main () {

    const char s[2] = ",";
    const char s2[2] = ":";

    char var1[] = "fiftyTwoWeekHigh\"";
    char *fiftyhigh;
    char *fiftyhigh2;
    char *fiftyhigh_token;
    char *fiftyhigh2_token;
   
    char var2[] = "fiftyTwoWeekLow\"";
    char *fiftylow;
    char *fiftylow2;
    char *fiftylow_token;
    char *fiftylow2_token;

    char var3[] = "regularMarketPrice\"";
    char *price;
    char *price2;
    char *price_token;
    char *price2_token;
   
    FILE *fp;
    char* data = "./data/";
    char* json = ".json";
    char line[MAX_LINES];
    char line2[MAX_LINES];
    int len;
    char* fichier = "./data/indices.txt";

    fp = fopen(fichier, "r");

    if (fp == NULL){
        printf("Impossible d'ouvrir le fichier %s", fichier);
        return 1;
    }

    while (fgets(line, sizeof(line), fp) != NULL) {
        char fname[10000];
        len = strlen(line);
        if (line[len-1] == '\n') {
            line[len-1] = 0;
        }
        
        int ret = snprintf(fname, sizeof(fname), "%s%s%s", data, line, json);
        if (ret < 0) {
            abort();
        }
        printf("%s\n", fname);
        
        FILE* f = fopen(fname, "r");

        while ( fgets( line2, MAX_LINES, f ) != NULL ) {
            fiftyhigh = strstr(line2, var1);
            fiftyhigh_token = strtok(fiftyhigh, s);
            fiftyhigh2 = strstr(fiftyhigh_token, s2);
            fiftyhigh2_token = strtok(fiftyhigh2, s2);
            printf("%s\n", fiftyhigh2_token);

            fiftylow = strstr(line2, var2);
            fiftylow_token = strtok(fiftylow, s);
            fiftylow2 = strstr(fiftylow_token, s2);
            fiftylow2_token = strtok(fiftylow2, s2);
            printf("%s\n", fiftylow2_token);

            price = strstr(line2, var3);
            price_token = strtok(price, s);
            price2 = strstr(price_token, s2);
            price2_token = strtok(price2, s2);
            printf("%s\n", price2_token);
        
            //printf("\n%s\t%s\t%s\t%s\t%s", line, calculcx(fiftyhigh2_token, price2_token, fiftylow2_token), "DIV-1", price2_token, "test");
            
        }
        fclose(f);
    }
    fclose(fp);
    return 0;
}

output 是:

./data/k.json
13.59
5.31
8.7
./data/BCE.json
60.14
46.03
56.74
./data/BNS.json
80.16
46.38
78.73
./data/BLU.json
16.68
2.7
Segmentation fault

這就像我的程序停止,因為它無法到達某個文件的某個數據......有沒有辦法分配更多的 memory? 因為我的 MAX_LINES 已經設置為 6000。

  • 你是說'\0'嗎?
if (line[len-1] == '\n') {
  line[len-1] = 0;
}

我建議您使用gdb來查看段錯誤發生的位置以及原因。 我認為您不必分配更多的 memory。 但是可能會發生段錯誤,因為您沒有更多數據並且您仍然打印結果。

使用if(price2_token,=NULL) printf("%s\n"; price2_token); 例如。

我假設您文件中的行看起來像這樣:

{"fiftyTwoWeekLow":32,"fiftyTwoWeekHigh":100, ... }

換句話說,它是某種 JSON 格式。 我假設該行以“{”開頭,所以每一行都是 JSON object。

您將該行讀入line2 ,其中現在包含:

{"fiftyTwoWeekLow":32,"fiftyTwoWeekHigh":100, ... }\0

請注意結尾處的\0終止字符串。 另請注意,“fiftyTwoWeekLow”首先出現,事實證明這非常重要。

現在讓我們跟蹤這里的代碼:

fiftyhigh = strstr(line2, var1);
fiftyhigh_token = strtok(fiftyhigh, s);

首先你調用strstr來找到“fiftyTwoWeekHigh”的 position。 這將返回指向該行中該字段名稱的 position 的指針。 然后調用strtok來查找將這個值與下一個值分開的逗號。 我認為這就是 go 錯誤的開始。 調用strtok后, line2如下所示:

{"fiftyTwoWeekLow":32,"fiftyTwoWeekHigh":100\0 ... }\0

請注意, strtok已修改字符串:逗號已替換為\0 這樣您就可以將返回的指針fiftyhigh_token用作字符串,而不會看到逗號后面的所有內容。

fiftyhigh2 = strstr(fiftyhigh_token, s2);
fiftyhigh2_token = strtok(fiftyhigh2, s2);
printf("%s\n", fiftyhigh2_token);

接下來查找冒號,然后使用指向冒號的指針調用strtok 由於您傳遞給strok的分隔符是冒號,因此strtok忽略冒號並返回下一個標記(因為我們正在查看的字符串以“100”結尾,沒有更多的冒號)是 rest字符串,換句話說,數字。

所以你得到了你的號碼,但可能不是你預期的方式? strtok的第二次調用確實沒有意義,因為(假設 JSON 格式正確)“100”的 position 只是fiftyhigh2+1

現在我們嘗試找到“fiftyTwoWeekLow:”

fiftylow = strstr(line2, var2);
fiftylow_token = strtok(fiftylow, s);
fiftylow2 = strstr(fiftylow_token, s2);
fiftylow2_token = strtok(fiftylow2, s2);
printf("%s\n", fiftylow2_token);

這基本上是相同的過程,在你調用strtok之后, line2是這樣的:

{"fiftyTwoWeekLow":32\0"fiftyTwoWeekHigh":100\0 ... }\0

請注意,您只能找到“fiftyTwoWeekLow”,因為它位於該行中的“fiftyTwoWeekHigh”之前。 如果它是在之后出現的,那么由於之前在“fiftyTwoWeekHigh”之后添加的\0 ,您將無法找到它。 在這種情況下, strstr將返回 NULL,這將導致strtok返回 NULL,然后在將 Z6C3E226B4D4795D518AB341B0824 傳遞給strstr之后,您肯定會遇到 seg 錯誤

因此,代碼對字段在行中出現的順序非常敏感,並且它可能會失敗,因為您的某些行的字段順序不同。 或者,某些行可能只是缺少某些字段,這將產生相同的效果。

如果您正在解析 JSON,您應該真正使用為此目的設計的庫。 但是如果你真的想使用strtok那么你應該:

  1. 閱讀line2
  2. 調用strtok(line2, ",")一次,然后在循環中重復調用strtok(NULL, ",")直到它返回 null。 這會將行分解為每個看起來像"someField":100的標記。
  3. 從這些標記中的每一個中隔離字段名稱和值(只需調用strchr(token, ':')來查找值)。 這里不要調用strtok ,因為它會改變strtok的內部 state 並且您將無法使用strtok(NULL, ",")繼續處理該行。
  4. 測試字段名稱,並根據其值設置適當的變量。 換句話說,如果是“fiftyTwoWeekLow”字段,則設置一個名為fiftyTwoWeekLow 的變量。 您不必費心去除引號,只需將它們包含在您要比較的字符串中。
  5. 處理完所有標記( strtok返回 NULL)后,對您設置的變量執行一些操作。

您可能需要將",{}"作為分隔符傳遞給strtok ,以消除圍繞該行的任何打開和關閉的花括號。 或者您可以在每個令牌中查找它們,如果它們出現則忽略它們。

您還可以將"\"{},:"作為分隔符傳遞給strtok 。這將導致strtok發出字段名稱和值的交替序列。您可以調用strtok一次以獲取字段名稱,再次調用以獲取值,然后測試字段名稱並對值做一些事情。

使用strtok是解析 JSON 的一種非常原始的方法,但只要您的 JSON 僅包含簡單的字段名稱和數字並且不包含任何本身包含分隔符的字符串,它就可以工作。

暫無
暫無

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

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