Reputation: 64
I'm having some trouble reading in data from a file into an array of memory allocated structs in c. My relevant code is as follows:
//Struct that holds the restaurant information
typedef struct
{
char *name;
char *food;
double *price;
int *rating;
}RESTAURANT;
//Function to get all the reviews from the file
void reviews()
{
int numReviews, i;
char tempBuffer[BUFFER_SIZE]; //hold the user input
RESTAURANT *reviews; //create an array of structs
FILE *inputFile; //file pointer
inputFile = fopen(INPUT_FILE_NAME, "r"); //open the input file
//Get the number of reviews from the top of the file
fgets(tempBuffer, BUFFER_SIZE, inputFile);
sscanf(tempBuffer, "%d", &numReviews);
//Allocate enough space in the struct array for the number of reviews
reviews = malloc(sizeof(*reviews)*numReviews);
//Loop to allocate memory for each field in each struct
for(i = 0; i < numReviews; i++)
{
reviews[i].name = malloc(sizeof(char *));
reviews[i].food = malloc(sizeof(char *));
reviews[i].price = malloc(sizeof(double *));
reviews[i].rating = malloc(sizeof(int *));
}
//Loop to get each field for each struct from the file
//And store it in the struct array at the correct struct
for(i = 0; i < numReviews; i++)
{
fscanf(inputFile, "%s", reviews[i].name);
fscanf(inputFile, "%s", reviews[i].food);
fscanf(inputFile, "%lf", reviews[i].price);
fscanf(inputFile, "%d", reviews[i].rating);
}
And the file at reviews.txt is:
4
Chili's
AmericanizedMexican
10.95
3
BurgerKing
American
4.50
2
IHOP
American
9.50
1
OliveGarden
AmericanizedItalian
11.00
4
Reading in Chili's and AmericanizedMexican works fine. But when I try to print the price or rating of Chili's the price always prints 0.0
and the rating is always some huge number over 1 million. What am I doing wrong here? I'm guessing it must be either something with allocating the memory or something with the way I'm meant to read it in.
Upvotes: 0
Views: 1572
Reputation: 29126
I don't know, but storing scalar values like price and rating as allocated data via pointers seems strange. You can do that, but it adds a lot of allocation overhead. Remeber that you have to free
everything that you have allocated.
Besides that, you got the allocation wrong:
reviews[i].name = malloc(sizeof(char *));
reviews[i].food = malloc(sizeof(char *));
reviews[i].price = malloc(sizeof(double *));
reviews[i].rating = malloc(sizeof(int *));
You allocate memory to hold something the size of a pointer. You must allocate memory that can hold the thing pointed to. A useful allocation pattern is:
x = malloc(sizeof(*x));
for single values and
x = malloc(count * sizeof(*x));
for arrays of length count
. You do that already for reviews
. Your strings, i.e. char arrays, should be such arrays. So you should allocate:
reviews[i].name = malloc(MAX_LEN * sizeof(char));
reviews[i].food = malloc(MAX_LEN * sizeof(char));
reviews[i].price = malloc(sizeof(double));
reviews[i].rating = malloc(sizeof(int));
where MAX_LEN
is a more or less arbitrary limit that you must set and enforce. (For example, you should make sure that fscanf
never writes more than ´MAX_LEN` characters to the buffer; that includes the trailing null character.)
Your treatment of the scalar values is awkward. I'd change the struct to
typedef struct {
char *name;
char *food;
double price; // Store values, not pointers
int rating; // Same here
} RESTAURANT;
Throw out the allocation and scan directly into these fields, using the address operator &
to get a pointer:
fscanf(inputFile, "%lf", &reviews[i].price);
fscanf(inputFile, "%d", &reviews[i].rating);
Upvotes: 2
Reputation: 134356
your problem is
for(i = 0; i < numReviews; i++)
{
reviews[i].name = malloc(sizeof(char *));
reviews[i].food = malloc(sizeof(char *));
reviews[i].price = malloc(sizeof(double *));
reviews[i].rating = malloc(sizeof(int *));
}
Here, sufficient memory is not allocated.
do this
for(i = 0; i < numReviews; i++)
{
reviews[i].name = malloc(128 *sizeof(char));
reviews[i].food = malloc(128 *sizeof(char));
reviews[i].price = malloc(sizeof(double));
reviews[i].rating = malloc(sizeof(int));
}
EDIT:
The value 128 is used for demonstration purpose only, just to point out the erroneous part in OP's code.
Upvotes: 1