bibzuda7
bibzuda7

Reputation: 64

Scanning from a file into an array of Mallocated Structs? (c)

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

Answers (2)

M Oehm
M Oehm

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

Sourav Ghosh
Sourav Ghosh

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

Related Questions