我正在编写一个程序,它读取并解析CSV文件,使用CSV文件的内容填充结构,然后将结构写入二进制模式的文件。我通过对它进行标记并将每个标记写入struct来解析csv文件。 问题是,当我尝试将此结构写入数据文件时,文件内容显示一些特殊字符,即它写入任何随机值。我附加了我的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);
答案 0 :(得分:3)
您没有为要复制到输出文件中的结构数组以及结构中的字符数组成员分配任何内存。简单地复制从strtok()
返回的指针将不起作用,因为它指向strtok()
函数内的静态字符数组。因此,基本上在单次遍历while循环后,temp.AccountName
和temp.LastPaymentDate
都指向相同的内存位置。此外,正如chemuduntntar在上面指出的那样,当你写出结构时,你只是写出了内存指针...你的结构中没有实际的字符串数据,你所假设的是字符数组。
您有两种选择...要么使用静态存储声明结构以存储字符串数组,然后使用strcpy()
将数据从strtok()
复制到这些数组中,要么使用{{1}并为你的指针分配内存(只记得你以后必须释放这些指针,除非你想要内存泄漏)。
例如,你可以这样做:
malloc()
然后在你的while循环中,当你拨打#define MAXBUFSIZE 511
typedef struct
{
int AccountNumber;
char AccountName[MAXBUFSIZE + 1];
double AccountBalance;
double LastPaymentAmount;
char LastPaymentDate[MAXBUFSIZE + 1];
} Person;
时,你可以这样做:
strtok()
现在使用这种方法,你的结构中的实际数据并没有指向某个临时存储...这种方法的唯一缺点是,如果你超过512字节,那么你将剪切该数据。如果你在512字节以下,那么你将在字符数组的末尾填充所有零。
接下来,你需要声明一个地方:
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
或
Person myarray[10];
因为现在每次进行while循环时,你都会覆盖Person* myarray = calloc(10, sizeof(Person));
之前的值。因此,在某些时候,您需要将temp
结构复制到更永久的存储阵列中。例如,在你的while循环结束时你应该调用:
temp
最后,对于fwrite()的调用,我会略微改变它,所以它是这样的:
memcpy(&myarray[LOOPNUMBER], &temp, sizeof(Person));
同样,如果您使用for(i=0;i<10;i++)
{
fwrite(myarray, sizeof(Person), 10, fpData);
}
,malloc()
等指针,请务必在调用calloc()
之后释放该存储空间。
希望这有帮助,
杰森
答案 1 :(得分:0)
如果没有在结构中定义静态数组来存储字符串,我认为这不会很有效,目前当你将结构写入磁盘时 - 只写指针。