简体   繁体   中英

reading,parsing a csv file , populating a struct and then write struct to a data file

I am writing a program which reads and parses a CSV file, populates a struct with the contents of CSV file and then writes the struct to a file in binary mode. I am parsing csv fileby tokenizing it and writing each token to struct. The problem is that when I try to write this struct to data file, the file contents show some special character ie it writes any random value. I am attaching my output.dat file. Can anyone pls help me in finding uot where I am wrong? Thanks.

Here is my code:

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);

You're not allocating any memory for the array of structures you're trying to copy into your output file, as well as the character array members in your structure. Simply copying the pointer returned from strtok() will not work as that is pointing to a static character array inside the strtok() function. So basically after a single pass through your while-loop, both temp.AccountName and temp.LastPaymentDate are pointing to the same exact memory location. Furthermore as chemuduguntar pointed out above, when you write-out the structure, you're only writing out the memory pointers ... there is no actual string data in your structure for what you're assuming are character arrays.

You have two choices ... either declare your structure with static storage to store the string arrays and then use strcpy() to copy the data from strtok() into those arrays, or use malloc() and allocate memory for your pointers (just remember you'll have to free those pointers later unless you want memory leaks).

So for instance, you could do something like this:

#define MAXBUFSIZE 511

typedef struct  
{
    int AccountNumber;  
    char AccountName[MAXBUFSIZE + 1];  
    double AccountBalance;  
    double LastPaymentAmount;  
    char LastPaymentDate[MAXBUFSIZE + 1];  
} Person;

Then inside your while-loop, when you call strtok() you can do this:

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

Now with this approach there is actual data inside your structures that is not pointing to some temporary storage somewhere ... the only downside to this approach is that if you go over 512 bytes, then you'll clip that data. If you go under 512 bytes, then you will have all zeros padding out the end of the character arrays.

Next, somewhere you need to declare either:

Person myarray[10];

or

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

because right now every time you go through your while-loop, you're over-writing the previous value of temp . So at some point you need to copy your temp structure into more permanent storage array. For instance, at the end of your while-loop you should call:

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

Finally, for the call to fwrite() I would change that slightly so it's something like:

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

And again, if you use pointers with malloc() , calloc() , etc., be sure to free that storage afterwards by a call to free() .

Hope this helps,

Jason

我认为如果不在结构中定义用于存储字符串的静态数组就无法正常工作,目前,当您将结构写入磁盘时-仅在写入指针。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM