Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why am I not able to print out the fields of my struct type?

I had previously written some code (as practice) to write create a struct type ‘Data’ made up of an integer field and a string field (char*). I created 3 instances of the Data struct and wrote them to a data file.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

int main(void)
{
    typedef struct{
        int num;
        char* str;
    }Data;

    // Create data file
    FILE* fptr = fopen("stuff.dat", "wb");

    // Declare 3 Data structs and an array of Data structs
    Data data1, data2, data3, dataf[3];

    // Initialize the values of fields of each of the 3 Data structs
    data1.num = 5;
    data1.str = malloc(100);
    strcpy(data1.str, "Scott Pilgrim");
    data1.str = (char*) realloc(data1.str, strlen(data1.str) + 1);
    data2.num = 7;
    data2.str = malloc(100);
    strcpy(data2.str, "Dave Patel");
    data2.str = (char*) realloc(data2.str, strlen(data2.str) + 1);
    data3.num = 67;
    data3.str = malloc(100);
    strcpy(data3.str, "Matthew Skinner red riding hood");
    data3.str = (char*) realloc(data3.str, strlen(data3.str) + 1);
    
    // Write the data structs to the data file "stuff.dat" if the file pointer is not NULL
    // and close the file
    if(fptr != NULL){
        fwrite(&data1, sizeof(data1), 1, fptr);
        fwrite(&data2, sizeof(data2), 1, fptr);
        fwrite(&data3, sizeof(data3), 1, fptr);
        printf("%ld\n", ftell(fptr));
        fclose(fptr);
    }

    // Open data file for reading
    fptr = fopen("stuff.dat", "rb");

    // Read the data in the data file into the array of Data structs if the file pointer is 
    // not NULL and print the fields of each struct to the screen.
    if (fptr != NULL){
        for (int i = 0; i < 3; i++){
            fread((dataf+i), sizeof(data1), 1, fptr);
            printf("%d: %s", dataf[i].num, dataf[i].str);
            if (i != 2){
                printf(", ");
            }
            // printf("%d\n", feof(fptr)); -please ignore. I was trying to confirm  something
        }
        // printf("\n");
        // printf("%ld\n", ftell(fptr));
        // fseek(fptr, 1*sizeof(data1), SEEK_SET);
        // printf("%ld\n", ftell(fptr)); Please ignore. I was testing something
        fclose(fptr);
        
    }
    
    // Free up any memory allocated for the string fields of the Data structs
    free(dataf[0].str);
    free(dataf[1].str);
    free(dataf[2].str);
    free(data1.str);
    free(data2.str);
    free(data3.str);
    return 0;
}

Lets call the above code program.c. It ran as expected. Now begins my problem in another code which I wrote to read the data only from the data file. Below is program2.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

typedef struct{
    int num;
    char* str;
}Data;

int main(void)
{
    // Open data file for reading
    FILE* fp = fopen("stuff.dat", "rb");
    
    // Allocate memory for storing a Data type struct
    Data* dataf = malloc(sizeof(Data));
    // dataf.str = malloc(100);
    // char s[100];
    if (fp != NULL){
        // printf("%ld\n", ftell(fp)); this was to check the position of the pointer
        // move pointer to the position of the last data written into the file
        fseek(fp, 2*sizeof(dataf), SEEK_SET);
        // print out position of pointer
        printf("%ld\n", ftell(fp));

        // Read data into the dataf Data struct
        fread(dataf, sizeof(Data), 1, fp);
        // Print position of pointer
        printf("%ld\n", ftell(fp));
        
      
        // (*dataf).str = (char*) malloc((strlen((*dataf).str) + 1));ignore please

        // print fields of dataf to screen
        printf("%d: %s\n", (*dataf).num, (*dataf).str);

        fclose(fp);
    }
    return 0;
}

Code in program2.c does not run. I mean it compiles but only prints out the pointer position but not the fields. I did switch up the code a bit where I read first and foremost into the address of the struct field num and then read into an array of characters and tried to store that array of characters into the str field of the struct. In that case I got only the num field printed out but null for the str field. How can solve the problem?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Your struct contains a pointer as one of its members. So when you write the struct to disk you’re writing the pointer value to disk, not the string that’s stored at that address. This works out alright when the same process that wrote the values is also reading, however when another process reads those pointer values they’re not valid, and attempting to dereference those value leads to undefined behavior.

You also have a double-free error in the first code as a result of this, as data1.str and dataf[0].str contain the same pointer value. The same holds for the other two.

You need to change the str member to have an array type, i.e. char str[100]. Then the actual strings will be written to disk, and you don’t need to worry about allocating space for that field.

So in both programs, change the struct definition to use an array instead of a pointer:

typedef struct{
    int num;
    char str[100];
}Data;

In the first program, remove the allocations for the str field:

data1.num = 5;
strcpy(data1.str, "Scott Pilgrim");
data2.num = 7;
strcpy(data2.str, "Dave Patel");
data3.num = 67;
strcpy(data3.str, "Matthew Skinner red riding hood");

And remove the calls to free at the end.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading