2015-02-12 6 views
1

У меня есть файл, который содержит data.csvfloat типа данных:fgets не читает полную строку в C


0.22,0.33,0.44

0.222,0.333,0.444


Мне нужно прочитать этот файл в двухмерном динамическом массиве. Но я не могу прочитать полную строку с fgets. Не знаете почему?

Вот мой C код, который я использовал на Ubuntu:

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

int main(int argc, char *argv[]) { 
    FILE *fp; 
    float **data;  
    int i,j,rows=2,cols=3; 
    char * token; 
    fp=fopen("data.csv","r"); 
    if(fp==NULL) { 
      fprintf(stderr,"Can't open input file"); 
      exit(1); 
    } 

    data= malloc(rows * sizeof(float*)); 
    char *rowbuffer=malloc(cols * (sizeof(float)+sizeof(char))); 
    i=0; 
    while(fgets(rowbuffer,sizeof(rowbuffer),fp) !=NULL) {  
     data[i] = malloc(cols * sizeof(float));  
     j=0; 
     printf("\n %s",rowbuffer); 
     for (token = strtok(rowbuffer,","); token != NULL; token = strtok(NULL, ",")) { 
      data[i][j++] = atof(token); 
      /*printf("%s",token);*/ 
     } 
     i++; 
    } 
    free(rowbuffer); 
    for(i = 0; i < rows; i++) 
     free(data[i]); 
    free(data); 
    fclose(fp); 
} 

Выход как:

0.22,0.

33,0.44

0.222,0

Ошибка в `./test ': двойной бесплатно или повреждение (уходит): 0x0000000000adf270

Прерывание (сбрасывание ядра)

Может кто-нибудь сказать, почему эта ошибка? :( Или есть лучший способ, чтобы прочитать этот тип файла данных

+2

'sizeof (rowbuffer) == sizeof (char *)' ... это, скорее всего, 4 или 8, в зависимости от аппаратного обеспечения. Поскольку вы * предполагаете *, это размер выделенного буфера, ваши предположения ошибочны. – DevSolar

+1

Возможный дубликат [Как найти «sizeof» (указатель, указывающий на массив)?] (Http://stackoverflow.com/questions/492384/how-to-find-the-sizeofa-pointer-pointingtoto -an-array) –

+1

Кроме того, отступы. Пробелы свободны. ;-) – DevSolar

ответ

2

Ваш кодирования проблема заключается в:

fgets(rowbuffer,sizeof(rowbuffer),fp) 

sizeof(rowbuffer) даст вам только размер указателя, а не размер из памяти, выделенной для указателя.

чтобы решить эту проблему, необходимо поставить правильный размер выделенной памяти [cols * (sizeof(float)+sizeof(char)] для fgets().

Вашей логической проблема заключается в:

Вы предположить, что печататься represntation из значения float будет принимать тот же объем памяти, как это требуется для этого из float переменных. Нет, это не так. В печатном представлении каждая цифра (включая десятичную точку и любую начальную или конечную 0 после десятичной) будет потреблять по одному байту памяти. Это следует учитывать при распределении памяти для целевого буфера.

+0

Но тогда размер выделенной памяти выглядит неправильно для предполагаемого использования. – SukkoPera

+1

@SukkoPera Правильно. Обновлял мой ответ. :-) –

4

Один вопрос здесь:

char *rowbuffer=malloc(cols * (sizeof(float)+sizeof(char))); 

sizeof(float) является размер, что поплавок использует в памяти, а не в текстовом представлении. При чтении из файлов вы должны выделить буфер, содержащий целую строку в текстовом формате. В вашем случае хорошая ставка может быть следующее:

int bufsize = cols * (3 + DBL_MANT_DIG - DBL_MIN_EXP + 1) + 1; 

(см это почему это значение и то, что вам нужно #include:. What is the maximum length in chars needed to represent any double value? Задний + 1 должен учитывать символ новой строки, которая fgets() делает читать и включите в буфер.)

Но это предполагает, что во входном файле нет ошибок форматирования, поэтому вам может потребоваться добавить дополнительное значение для этого значения.

После того как вы это значение, использовать его как в malloc() и fgets():

char *rowbuffer=malloc(bufsize); 
i=0; 
while(fgets(rowbuffer,bufsize,fp) !=NULL) { 
... 

На стороне записки, ваш входной файл выглядит, как он может быть лучше читать с помощью scanf().

+0

благодарит за комментарии. Я думаю, что память зарезервирована таким образом, используя 'bufsize' будет гораздо больше, чем фактически используется. Две вещи, связанные с моими файлами csv, состоят в том, что у меня нет предварительной информации о том, сколько строк и столбцов она имеет - может быть и тысяч или больше. Во-вторых, точность, используемая в отдельных значениях, может варьироваться, например, 0,124 или может быть 0,001204. – Kaur

+0

@Kaur: Ну, это очень зависит от того, как данные организованы в файле, который вы хотите прочитать. Если строки имеют ширину в несколько десятков символов (скажем, 80-100), что я и предполагал в вашем случае, использование линейного буфера обычно доступно, и вам даже не нужно его после завершения чтения. Если строки могут быть (намного) длиннее и/или если вы не знаете максимальную длину, вам придется прибегнуть к другому методу, который позволяет вам считывать одно значение за раз, например метод 'scanf()' Я предлагаю. Вы посмотрели на это? – SukkoPera

+0

@Kaur: О другой точности, ты потрудился взглянуть на ссылку, которую я тебе дал? – SukkoPera

Смежные вопросы