[英].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.