Strange value when reading from binary file with fread() in C - c

I have an issue that I can't solve...
I used fwrite to write an int value (among other values that come from a struct) into a file that I've opened using fopen(file, "wb");
This worked fine, and when I view the contents of the file, I can see the HEX value of the int that I've "written" (and all the other values as well).
Next, I try to read the file. So, I open the file using fopen(file, "rb"); and start reading it using fread. The first int value is read correctly (e.g. 7) and all the other values after it - which belong to the first struct that I've written.
I then try to read the next struct and when I try to read the first int value, I receive a very strange number (e.g. 1140850688) but it should be 39 instead.
So the question is: Why is this happening? And how can I solve it?
My struct looks like this:
struct a {
int a1;
char* a2;
struct b* a3;
unsigned char a4;
int a5;
char* a6;
}
And the fread call looks like this: fread(&(tmpA->a1), sizeof(int), 1, file);
EDIT:
The fwrite part:
fwrite(&(tmpA->a1), sizeof(int), 1, file);
fwrite(tmpA->a2, sizeof(char), strlen(tmpA->a2), file);
fwrite(tmpA->a3, sizeof(struct b), 1, file);
fwrite(&(tmpA->a4), sizeof(unsigned char), 1, file);
fwrite(&(tmpA->a5), sizeof(int), 1, file);
fwrite(tmpA->a6, sizeof(char), strlen(tmpA->a6), file);
The fread is almost the same.

I suspect your problem is on this line
fwrite(tmpA->a3, sizeof(struct b), 1, file);
where you are writing a struct. This struct will have padding bytes, as per this wikipedia article which will offset the rest of your data. You will likely have to come up with a better way of writing that struct to memory. This page provides additional explanation.
You can check to see if this is indeed the problem by checking if a4 has the value you expect, or by comparing the size of the entire struct versus the sum of the sizes of its members.
Also, these lines look dangerous:
fwrite(tmpA->a2, sizeof(char), strlen(tmpA->a2), file);
fwrite(tmpA->a6, sizeof(char), strlen(tmpA->a6), file);
they say that the length of the string being printed may vary in your stored data. strlen will give you the length of your string without counting the terminating \0 so there is no good way to know where a string ends once you've written it. I can't imagine how you plan on reading the string back in.

If you wrote a struct from a file, you should read a struct back; trying to read an int is not going to work. However, it rarely, if ever, makes sense two write out as binary a struct that contains pointers. You should either make them arrays of fixed size, or serialize them separately from your struct.
EDIT : (in response to posted code) Most likely the problem has to do with writing an unknown number of characters in the second call of fwrite. When you serialize a C string, you should write out the number of characters before writing the characters themselves, so that when you read you'd know how much characters to allocate and to read back:
int len = strlen(tmpA->a2);
fwrite(&len, sizeof(int), 1, file);
fwrite(tmpA->a2, sizeof(char), len, file);
...
fread(&(tmpA->a1), sizeof(int), 1, file);
tmpA->a2 = malloc(tmpA->a1+1);
fread(tmpA->a2, sizeof(char), tmpA->a1, file);
tmpA->a2[tmpA->a1] = '\0';

Related

How does fread() know where to look in a .wav file? [duplicate]

Simple question,
When i use fread:
fread(ArrayA, sizeof(Reg), sizeBlock, fp);
My file pointer, fp is moved ahead?
Answer: Yes, the position of the file pointer is updated automatically after the read operation, so that successive fread() functions read successive file records.
Clarification: fread() is a block oriented function. The standard prototype is:
size_t fread(void *ptr,
size_t size,
size_t limit,
FILE *stream);
The function reads from the stream pointed to by stream and places the bytes read into the array pointed to by ptr, It will stop reading when any of the following conditions are true:
It has read limit elements of size size, or
It reaches the end of file, or
A read error occurs.
fread() gives you as much control as fgetc(), and has the advantage of being able to read more than one character in a single I/O operation. In fact, memory permitting, you can read the entire file into an array and do all of your processing in memory. This has significant performance advantages.
fread() is often used to read fixed-length data records directly into structs, but you can use it to read any file. It's my personal choice for reading most disk files.
Yes, calling fread does indeed move the file pointer. The file pointer will be advanced by the number of bytes actually read. In case of an error in fread, the file position after calling fread is unspecified.
Yes, The fp will be advanced by the total amount of bytes read.
In your case the function fread reads sizeBlock objects, each sizeof(Reg) bytes long, from the stream pointed to by fp, storing them at the location given by ArrayA.
Yes, it does. It could be checked by using ftell() function in order to show current position (in fact, bytes read so far), take a look it:
int main() {
typedef struct person {
char *nome; int age;
} person;
// write struct to file 2x or more...
FILE *file = fopen(filename, "rb");
person p;
size_t byteslength = sizeof(struct person);
printf("ftell: %ld\n", ftell(file));
fread(&p, byteslength, 1, file);
printf("name: %s | age: %d\n", p.nome, p.idade);
printf("ftell: %ld\n", ftell(file));
fread(&p, byteslength, 1, file);
printf("name: %s | age: %d\n", p.nome, p.idade);
//...
fclose(file);
return 0;
}

Convert ngx_chain_t into buffer memory

I'm looking for the way to convert ngx_chain_t object (with is already filled by nginx and ready response to client or pass to another filter) to buffer memory just like when we read the whole file into memory like this:
#include <stdio.h>
#define MAX 999999
char source[MAX + 1];
FILE *fp = fopen("thisfile", "r");
size_t newLen = fread(source, sizeof(char), MAX, fp);
source[++newLen] = '\0';
Now source is buffer memory that hold the whole content of thisfile in memory.
Is there any way to convert ngx_chain_t buffer into something likes source in this case?
Try fmemopen(3), read the man page 1st!
Maybe I did not understand the question.
But as I understood it, it was about replacing the fopen into something else the could read the inx_chain_t object structure like:
...
fp = fmemopen(object, MAX, "r");
newLen = fread(source, sizeof(char), MAX, fp);
...
Sorry if this still is a misunderstanding.

Does fread move the file pointer?

Simple question,
When i use fread:
fread(ArrayA, sizeof(Reg), sizeBlock, fp);
My file pointer, fp is moved ahead?
Answer: Yes, the position of the file pointer is updated automatically after the read operation, so that successive fread() functions read successive file records.
Clarification: fread() is a block oriented function. The standard prototype is:
size_t fread(void *ptr,
size_t size,
size_t limit,
FILE *stream);
The function reads from the stream pointed to by stream and places the bytes read into the array pointed to by ptr, It will stop reading when any of the following conditions are true:
It has read limit elements of size size, or
It reaches the end of file, or
A read error occurs.
fread() gives you as much control as fgetc(), and has the advantage of being able to read more than one character in a single I/O operation. In fact, memory permitting, you can read the entire file into an array and do all of your processing in memory. This has significant performance advantages.
fread() is often used to read fixed-length data records directly into structs, but you can use it to read any file. It's my personal choice for reading most disk files.
Yes, calling fread does indeed move the file pointer. The file pointer will be advanced by the number of bytes actually read. In case of an error in fread, the file position after calling fread is unspecified.
Yes, The fp will be advanced by the total amount of bytes read.
In your case the function fread reads sizeBlock objects, each sizeof(Reg) bytes long, from the stream pointed to by fp, storing them at the location given by ArrayA.
Yes, it does. It could be checked by using ftell() function in order to show current position (in fact, bytes read so far), take a look it:
int main() {
typedef struct person {
char *nome; int age;
} person;
// write struct to file 2x or more...
FILE *file = fopen(filename, "rb");
person p;
size_t byteslength = sizeof(struct person);
printf("ftell: %ld\n", ftell(file));
fread(&p, byteslength, 1, file);
printf("name: %s | age: %d\n", p.nome, p.idade);
printf("ftell: %ld\n", ftell(file));
fread(&p, byteslength, 1, file);
printf("name: %s | age: %d\n", p.nome, p.idade);
//...
fclose(file);
return 0;
}

Write pointer to file in C

I have a structure:
typedef struct student {
char *name;
char *surname;
int age;
} Student;
I need to write the structure into a binary file.
Here is my attempt :
Student *s = malloc(sizeof(*s));
I fill my structure with data and then I write the struct into the file with :
fwrite(s, sizeof(*s), 1, fp);
In my file, name and surname don't exist. Instead they have their respective address of their char * pointer.
How can I write a char * into a file instead of the address of the pointer ?
You need to dereference your pointer and write the parts of the struct. (You should not fwrite a struct directly, but rather encode its parts and write those:
Student *s = malloc(sizeof(*s));
s->name = "Jon";
s->surname = "Skeet";
s->age = 34;
// ....
fwrite(s->name, sizeof(char), strlen(s->name) + 1, fp);
fwrite(s->surname, sizeof(char), strlen(s->surname) + 1, fp);
//This one is a bit dangerous, but you get the idea.
fwrite(&(s->age), sizeof(s->age), 1, fp);
You will have to do some extra work to write out the data pointed to by the structure elements - probably just write it out element by element.
Alternatively change your structure to something like this:
typedef struct
{
char name[MAX_NAME_LEN];
char surname[MAX_SURNAME_LEN];
int age;
} Student;
if you want to directly write the structure as it is to a file you would want to define the sizes of name and surname rather than dynamically allocating it.
typedef structure student { char name[100]; char surname[100]; int age; }
else you will need to write each info in the structure one by one.
In C, you have to serialize structures (convert them to a series of bytes) manually. If you want the data you output to be readable by another machine, you have to take endianness account endianness.
Here's a simple example of serializing your structure (writing it to a file), disregarding endianness/differing word size and making the code unportable:
size_t length;
length = strlen(s->name) + 1;
fwrite(&length, sizeof(length), 1, fp);
fwrite(s->name, 1, length, fp);
length = strlen(s->surname) + 1;
fwrite(&length, sizeof(length), 1, fp);
fwrite(s->surname, 1, length, fp);
fwrite(&s->age, sizeof(s->age), 1, fp);
And to unserialize:
size_t length;
fread(&length, sizeof(length), 1, fp);
s->name = malloc(length);
fread(s->name, 1, length, fp);
fread(&length, sizeof(length), 1, fp);
s->surname = malloc(length);
fread(s->surname, 1, length, fp);
fread(&s->age, sizeof(s->age), 1, fp);
In a real application, you should check the validity of your input rather than blindly assuming the input is valid and trustworthy. Also, you need to decide what byte order you'll use to store your ints, size_ts, etc, and make sure you read/write them in the correct byte order by using bit shifting.
By the way, you may want to look at tpl, a simple binary serialization library for C.
You need to dereference s and individually write out each element of the structure to actually write thecontents to the file:
size_t nameCount = strlen(s->name) + 1;
fwrite(s->name, sizeof(char), nameCount, fp);
size_t surnameCount = strlen(s->surname) + 1;
fwrite(s->surname, sizeof(char), surnameCount, fp);
Note that anyway you won't be able to see the fields in a 'normal' form because you write it to a binary file. Try to open the file without the "b" in the mode argument of fopen (r+\ w\ a etc. instead of rb+\ wb\ ab).
You can see that when using fread (from the binary file, after opening it in "rb" mode you should get the structure fields as expected.
You'll have to write out the fields individually, as others have said. One thing which may help reading back the data is to write out the string lengths before each entry, eg.
size_t len;
len = strlen(s->name)+1;
fwrite(&len,sizeof(len),1,stream);
fwrite(s->name,sizeof(*(s->name)),len,stream);
...
Reading back is then a matter of
Student * s = malloc(sizeof(*s));
size_t len;
fread(&len,sizeof(len),1,stream);
s->name = malloc(len);
fread(s->name,sizeof(*(s->name)),len,stream);
...

C - Saving a Small File As a String

Hey guys...In C, I wish to read a file in my current working directory (nothing fancy), into a string. Later, I'd like to print that string out so I can do some work on it. I'm more used to Java, so I'm getting my chops on C and would love an explanation on how to do this! Thanks fellas...
Here's a C program that will read a file and print it as a string. The filename is passed as an argument to the program. Error checking would be a good thing to add.
int main(int argc, char *argv[])
{
FILE *f;
char *buffer;
size_t filesize;
f = fopen(argv[1], "r");
// quick & dirty filesize calculation
fseek(f, 0, SEEK_END);
filesize = ftell(f);
fseek(f, 0, SEEK_SET);
// read file into a buffer
buffer = malloc(filesize);
fread(buffer, filesize, 1, f);
printf("%s", buffer);
// cleanup
free(buffer);
return 0;
}
You will use:
FILE *f = fopen(filename, "r");
To open the file. If that returns non-null, you can use:
char buf[MAXIMUM_LINE_SIZE]; /* pick something for MAXIMUM_LINE_SIZE... */
char *p;
while ((p=fgets(buf, sizeof(buf), f)))
{
/* Do something with the line pointed to by p */
}
To do something more sophisticated (not bounded by an arbitrary size, or spanning multiple lines) you'll want to learn about dynamic memory allocation: the functions malloc(), realloc(), free()...
Some links to help you:
manpages for file I/O: fopen, fgets, fclose
for memory allocation: malloc
Also, just to throw it out there: If you are interested in writing C++ instead of C, that also has its own file I/O and string stuff that you may find helpful, and you won't have to do all the memory allocations yourself. But even then, it's probably good to understand the C way also.
You might start with fopen and fread.

Resources