чтение, синтаксический анализ CSV-файла, заполнение структуры и запись структуры в файл данных - PullRequest
1 голос
/ 01 апреля 2011

Я пишу программу, которая читает и анализирует файл CSV, заполняет структуру содержимым файла CSV, а затем записывает структуру в файл в двоичном режиме. Я анализирую CSV-файл, разбивая его на токены и записывая каждый токен в struct. Проблема в том, что когда я пытаюсь записать эту структуру в файл данных, содержимое файла показывает какой-то специальный символ, то есть оно записывает любое случайное значение. Я прилагаю свой файл output.dat. Может кто-нибудь, пожалуйста, помогите мне найти, где я не прав? Спасибо.

Вот мой код:

typedef struct  
{
    int AccountNumber;  
    char    *AccountName;  
    double  AccountBalance;  
    double  LastPaymentAmount;  
    char    *LastPaymentDate;  
} Person;

FILE    *fpData;        

Person temp = {0,"",0,0,0};

if ( ( fpData = fopen( "input.csv", "r" ) ) == NULL ) //Reading a file
{
    printf( "File could not be opened.\n" );
}

while(fgets(buf, BUFFER_SIZE, fpData) != NULL)
{
    /* Here we tokenize our string and scan for " \n" characters */

    // for(tok = strtok(buf,"\n");tok;tok=strtok(NULL,"\n"))
    // {
        tok = strtok(buf, ",");
        temp.AccountNumber = atoi(tok); 
        printf(" %i ",temp.AccountNumber );

        tok = strtok(NULL, ",");

        temp.AccountName = tok;
        printf("%s ",temp.AccountName );

        tok = strtok(NULL, ",");

        temp.AccountBalance = atof(tok);
        printf("temp.AccountBalance = %f ",temp.AccountBalance );

        tok = strtok(NULL, ",");

        temp.LastPaymentAmount = atof(tok);
        printf("temp.LastPaymentAmount = %f ",temp.LastPaymentAmount );

        tok = strtok(NULL, ",");

        temp.LastPaymentDate = tok;  
        printf("temp.LastPaymentDate = %s ",temp.LastPaymentDate );

        tok = strtok(NULL, ",");
        printf("\n");                 
    // }  
}

if ( ( fpData = fopen( "output.dat", "wb" ) ) == NULL )  
{  
   printf( "File could not be opened.\n" );  
}  
else  
{  
    printf("\nFileName is:%s\n",argv[2]);  
    printf("File will be overwritten. Do you want to continue?\nPress Y if yes, N if no");  
    printf("\n?\n");  
    scanf("%c", &choice);  

    if(choice=='Y')         
    {  
        for(i=0;i<10;i++)  
        {  
            fwrite(&temp, sizeof(temp), 10, fpData);  
        }           
    }  
}  

fclose(fpData);

Ответы [ 2 ]

3 голосов
/ 02 апреля 2011

Вы не выделяете память для массива структур, которые вы пытаетесь скопировать в выходной файл, а также для элементов массива символов в вашей структуре.Простое копирование указателя, возвращенного из strtok(), не будет работать, поскольку оно указывает на статический массив символов внутри функции strtok().Таким образом, в основном, после одного прохода через цикл while, и temp.AccountName, и temp.LastPaymentDate указывают на одну и ту же область памяти.Кроме того, как было отмечено выше в chemuduguntar, когда вы записываете структуру, вы записываете только указатели памяти ... в вашей структуре нет фактических строковых данных , которые, как вы полагаете, являются символьнымимассивы.

У вас есть два варианта ... либо объявить вашу структуру со статическим хранилищем для хранения строковых массивов, а затем использовать strcpy() для копирования данных из strtok() в эти массивы, либо использовать malloc()и выделите память для ваших указателей (только помните, что вам придется освобождать эти указатели позже, если вы не хотите утечек памяти).

Так, например, вы могли бы сделать что-то вроде этого:* Затем внутри вашего цикла while, когда вы вызываете strtok(), вы можете сделать это:

tok = strtok(NULL, ",");
strncopy(temp.AccountName, tok, MAXBUFSIZE);
temp.AccountName[MAXBUFSIZE] = '\0'; //safety NULL termination

//...more code

tok = strtok(NULL, ",");
strncopy(temp.LastPaymentDate, tok, MAXBUFSIZE);
temp.LastPaymentDate[MAXBUFSIZE] = '\0'; //safety NULL termination

Теперь при таком подходе в ваших структурах есть фактические данные, которые не указывают на какое-то временное хранилище где-нибудьЕдинственным недостатком этого подхода является то, что если вы превысите 512 байт, вы обрежете эти данные.Если у вас меньше 512 байт, то у вас будут все нули, дополняющие конец массивов символов.

Далее, где-то вам нужно объявить:

Person myarray[10];

или

Person* myarray = calloc(10, sizeof(Person));

потому что прямо сейчас каждый раз, когда вы проходите цикл while, вы перезаписываете предыдущее значение temp.Поэтому в какой-то момент вам нужно скопировать структуру temp в более постоянный массив хранения.Например, в конце вашего цикла while вы должны вызвать:

memcpy(&myarray[LOOPNUMBER], &temp, sizeof(Person)); 

Наконец, для вызова fwrite () я бы немного изменил это так:

for(i=0;i<10;i++)  
{  
    fwrite(myarray, sizeof(Person), 10, fpData);  
} 

И снова, если вы используете указатели с malloc(), calloc() и т. Д., Обязательно освободите это хранилище после вызова free().

Надеюсь, это поможет,

Jason

0 голосов
/ 01 апреля 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...