I'm trying to read data from a csv file into a struct. The struct contains int, char and float members. I'm getting errors back except for the char member. I'm fairly new to C so I appreciate your help!
Data from csv file "Order":
0, cafe, 3.90, 0
0, espresso, 3.50, 0
...
My struct:
typedef struct {
int position;
char name[20];
float price;
int counter;
}drink;
void init(drink *pt)
{
FILE *fp;
char buf[50];
int i = 0, j;
fp=fopen("Order", "r");
while( fgets(buf,sizeof(buf),fp) != NULL)
{
strcpy(pt[i].position, strtok(buf,","));
strcpy(pt[i].name, strtok(NULL,","));
strcpy(pt[i].price, strtok(NULL,","));
strcpy(pt[i].counter, strtok(NULL,","));
++i;
}
}
int main()
{
int number = NR;
int d=0;
drink bar[number];
drink *pt = &bar[0];
welcome();
init(pt);
...
return 0;
}
- Wrong copy.
Do not use strcpy()
to copy a string to an int
. Rather convert it.
// strcpy(pt[i].position, strtok(buf,","));
char *endptr;
pt[i].position = strtol(strtok(buf,","), &endptr, 10);
// or
pt[i].position = atoi(strtok(buf,","));
...
pt[i].price = strtod(strtok(NULL,","), &endptr);
(Note: Various error checking omitted)
- Enable all compiler warnings. This will save you time as your compiler should have caught this.
- If you were getting errors, compile time or run time, post the error
rather than weakly describe the error as "getting errors back".
You are not using strcpy correct.
You should only use it with char buffers, not with integers and floats.
Read man strcpy for more information about it.
// to extract a integer from a char buffer into a int value, use atoi() not strcpy
// to extract a float from a char buffer into a float value, use atof(), not strcpy
// the last field in a line probably does not have a trailing ','
// and the last field should already be '\0' terminated by the fgets
// so the code should use something else to get a pointer to the last field
// the calls to strtok() should be setting a char* field from the returned value
// then
// 1) that value can be checked for NULL
// 2) getting a pointer to the last field would be
// returnedValue+=2;
// (the 2 to skip over the intervening ' ' after the converted comma
// all the copying/converting of the fields need to advance the
// returnedValue by 1 to skip over the leading ' ',
// except the first field, which has no leading ' '
// the #define for 'NR' should be used in the function so as to
// not overflow the available number of input fields
// for most of the break; statements, you may want to add a printf
// so the user knows what happened
// suggest:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NR (20)
#define MAX_NAME_LEN (20)
typedef struct
{
int position;
char name[MAX_NAME_LEN];
float price;
int counter;
} drink;
void init(drink *pt)
{
char buf[50];
int i = 0; // loop counter
//int j = 0; // comment out or compiler will raise a warning about unused variable
char * returnFromStrtok = NULL;
FILE *fp = NULL;
if( NULL == (fp=fopen("Order", "r")) )
{ // then, fopen failed
perror( "fopen failed for: Order" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
for( i = 0; i<NR; i++)
{
if( NULL == fgets(buf,sizeof(buf),fp) ) break;
returnFromStrtok = strtok(buf, ",");
if( NULL == returnFromStrtok ) break;
pt[i].position = atoi(returnFromStrtok);
returnFromStrtok = strtok(NULL, ",");
if( NULL == returnFromStrtok ) break;
// step past leading ' '
returnFromStrtok++;
if( MAX_NAME_LEN <= strlen( returnFromStrtok ) )
{ // bad field, too long
memset( pt[i].name, '*', MAX_NAME_LEN ); // indicate invalid field
}
else
{
strcpy(pt[i].name, returnFromStrtok );
}
returnFromStrtok = strtok(NULL, ",");
if( NULL == returnFromStrtok ) break;
// step past leading ' '
returnFromStrtok++;
pt[i].price = atof(returnFromStrtok);
// +2 steps by '\0' and ','
returnFromStrtok += strlen(returnFromStrtok)+2;
pt[i].counter = atoi(returnFromStrtok);
} // end for
} // end function: init