簡體   English   中英

.txt與.csv解析C

[英].txt vs .csv parsing C

我創建了一個代碼,該代碼將使用C將.txt文件解析為雙精度數組。我的.txt文件經過格式化,因此每個點都由“,”分隔。 現在,我想讓此代碼解析相同的數據,但來自.csv文件。 更改文件類型時,我收到分段錯誤。

為什么會發生這種情況? 我是否相信以相同的方式讀取這兩種文檔類型是否正確?

這篇文章的主要問題是,閱讀.txt和.csv有什么區別?

/* 
* Calibration File Read Test
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main ()
{
    FILE *myfile = fopen ( "BarEast.txt", "r" );
    /* I want to change this file type to .csv */

    /* opening file for reading */
    if(myfile == NULL) 
    {
        printf("Error opening file");
        return(-1);
    }

    int i = 0;
    int j, k;

    char *result[361] = {0};
    char line[10];
    char *value;

    while(fgets(line, sizeof(line), myfile))
    {
        value = strtok(line, ",");
        result[i] = malloc(strlen(value) + 1);
        strcpy(result[i], value); 
        i++;
    }

    double val;
    double cal[361] = {0};

    for(k = 0; k < 361; k++)
    {
        val = atof(result[k]);
        cal[k] = val;
    }

    for(j = 0; j < 361; j++)
    {
        printf("Element[%d] = %f\n", j, cal[j]);
    }
    fclose(myfile);
    return 0;

}

問題不在於文件名,而是文件具有不同的內容。 不同的內容暴露了代碼中的內存問題。

立刻我的目光注視着到處都是硬編碼的361 假設輸入文件中將有361行,並且存在您的段錯誤。 val = atof(result[k]);發生在第40行(使用valgrind標識val = atof(result[k]); 走出result數組。 C語言對於硬代碼大小非常誘人 不要這樣做,尤其是對於輸入,這是您不能依靠的拐杖。

而是代碼必須適應文件中字段和行的數量。 您可以使用realloc編寫自己的動態數組代碼,但是有很多C庫可以幫您做到這一點,而且效果更好。 我了解GLib的基礎知識。

另一個問題是每行只分配了10個字節。 這個很小。 這意味着fgets不斷走斷line ,如果是超過9個字符(它會)。 從輸入讀取數據時,任何形式的靜態內存分配都會出現問題。 使用getline代替fgets避免了每行分配多少內存的問題。 getline會為您解決這個問題。 注意, getline重復使用line ,因此,如果要更改line ,則需要首先對其進行strdup

/* 
* Calibration File Read Test
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <glib.h>

int main (int argc, char **argv)
{
    /* Check we got the right number of arguments. */
    if( argc != 2 ) {
        fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
        return -1;
    }

    /* Open the file */
    FILE *fp = fopen ( argv[1], "r" );
    if(fp == NULL) 
    {
        fprintf(stderr, "Error opening file %s for reading.\n", argv[1]);
        return(-1);
    }

    /* A dynamic array which will grow as needed */
    GArray *result = g_array_new(TRUE, TRUE, sizeof(char *));

    /* Read each line using getline which does the line memory allocation
       for you. No buffer overflow to worry about. */
    char *line = NULL;
    size_t linecap = 0;
    while(getline(&line, &linecap, fp) > 0) {
        /* This will only read the first cell. Exercise left for the reader. */
        char *value = strtok(line, ",");
        if( value == NULL ) {
            fprintf(stderr, "Could not parse %s\n", line);
            continue;
        }

        char *field = malloc(strlen(value) + 1);
        strcpy(field, value);

        g_array_append_val(result, field);
    }

    free(line);
    fclose(fp);

    /* Iterate through the array using result->len to know the length */
    for(int i = 0; i < result->len; i++)
    {
        printf("Element[%d] = %s\n", i, g_array_index(result, char *, i));
    }

    /* Free the array */
    g_array_free(result, TRUE);

    return 0;

}

我刪除了atof轉換,因為它分散了主要問題。 您可以根據需要將其放回去。

這仍然有一個問題,即它僅讀取每行的第一個單元格。 我將其保留給您。

您在此代碼中的轉換atof

for(k = 0; k < 361; k++)
{
    val = atof(result[k]);
    cal[k] = val;
}

超出數組“結果”的范圍
只有將數據放入結果數組中時,才將內存分配給結果數組中的元素

result[i] = malloc(strlen(value) + 1);

如果創建的記錄少於361條,則表示您正在從未分配的內存中讀取數據-因此出錯。

您需要記錄已讀入的結果數,然后使用該值來確保在處理結果數組時保持在范圍內。

基於文件擴展名的文件之間沒有區別。

暫無
暫無

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

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