Reading a file and filling out a structure

I have a structure with the following definition:

typedef struct myStruct{ int a; char* c; int f; } OBJECT; 

I can fill this object and write it to a file. However, I cannot read the char * c value in it ... when I try to read it, it gives me a segmentation error error. Something is wrong with my code:

 //writensave.c #include "mystruct.h" #include <stdio.h> #include <string.h> #define p(x) printf(x) int main() { p("Creating file to write...\n"); FILE* file = fopen("struct.dat", "w"); if(file == NULL) { printf("Error opening file\n"); return -1; } p("creating structure\n"); OBJECT* myObj = (OBJECT*)malloc(sizeof(OBJECT)); myObj->a = 20; myObj->f = 45; myObj->c = (char*)calloc(30, sizeof(char)); strcpy(myObj->c, "This is a test"); p("Writing object to file...\n"); fwrite(myObj, sizeof(OBJECT), 1, file); p("Close file\n"); fclose(file); p("End of program\n"); return 0; } 

This is how I try to read it:

 //readnprint.c #include "mystruct.h" #include <stdio.h> #define p(x) printf(x) int main() { FILE* file = fopen("struct.dat", "r"); char* buffer; buffer = (char*) malloc(sizeof(OBJECT)); if(file == NULL) { p("Error opening file"); return -1; } fread((void *)buffer, sizeof(OBJECT), 1, file); OBJECT* obj = (OBJECT*)buffer; printf("obj->a = %d\nobj->f = %d \nobj->c = %s", obj->a, obj->f, obj->c); fclose(file); return 0; } 
+4
source share
5 answers

When you write your object, you write the value of the pointer to a file instead of the pointer information.

What you need to do is not just fwrite / fread your entire structure, but rather do this field at a time. fwrite a and f, as you do with an object, but then you need to do something special with the string. Try fwrite / fread lengths (not represented in your data structure, this is great) and then fwrite / fread character buffer. When reading, you will need to highlight this, of course.

+2
source

The first code example assumes that the lines will be no more than 30 characters. If so, then the easiest fix is ​​probably to override your structure as follows:

 typedef struct myStruct{ int a; char c[30]; int f; } OBJECT; 

Otherwise, you simply store a pointer to dynamically allocated memory, which will be destroyed when your program exits (therefore, when you later receive this pointer, the address is useless and most likely will not be accessible).

+2
source

You store a pointer to a char, not a string. When you try to reload the file you are using in a new process with a different address space, and this pointer is no longer valid. Instead, you need to save the string by value.

+1
source

I would like to add a note about a potential portability problem that may or may not exist depending on the intended use of the data file.

If the data file must be divided between computers of varying degrees, you will need to configure converters between files and hosts for char files (int, short, long, long, long ...). Moreover, it would be wise to use the types from stdint.h (int16_t, int32_t, ...) instead, to guarantee the right size.

However, if the data file will not be moved anywhere, then ignore these two points.

+1
source

The char * field of your structure is known as a variable-length field. When you write this field, you will need a method for determining the length of the text. Two popular methods:
1. Letter size first
2. Recording a terminal symbol

Writing the first size
In this method, the size of the text data is written first, then the data immediately.
Advantages: text can load faster with block reading.
Disadvantages: two readings required, additional space for data length.
Example code snippet:

 struct My_Struct { char * text_field; }; void Write_Text_Field(struct My_Struct * p_struct, FILE * output) { size_t text_length = strlen(p_struct->text_field); fprintf(output, "%d\n", text_length); fprintf(output, "%s", p_struct->text_field); return; } void Read_Text_Field(struct My_STruct * p_struct, FILE * input) { size_t text_length = 0; char * p_text = NULL; fscanf(input, "%d", &text_length); p_text = (char *) malloc(text_length + sizeof('\0')); if (p_text) { fread(p_text, 1, text_length, input); p_text[text_length] = '\0'; } } 

Writing a terminal character In this method, text data is written, followed by the "end" character. Very similar to the C language string. Advantages: Requires less space than Size First. Disadvantages: the text must be read one byte at a time, so the terminal character is not skipped.

Fixed size field
Instead of using char* as a member, use char [N] , where N is the maximum size of the field. Advantages: Fixed-size records can be read as blocks. Makes random access to files easier. Disadvantages: Space waste if the entire field space is not used. Problems when the field size is too small.

When writing data structures to a file, you should consider using a database . There are smaller ones like SQLite and larger ones like MySQL. Do not waste time writing and debugging persistent storage programs when they have already been written and tested.

+1
source

Source: https://habr.com/ru/post/1308801/


All Articles