fwrite() not working to write integer in binary file - c

Can someone tell my why won't this function work? I just can't get it...
void writeRegister(FILE *arq, Book *L){ //writes in actual file position
char c = '|';
int sizeRegWrite = reglen(L); //reglen() returns the size of Book
fwrite(&sizeRegWrite, sizeof(int), 1, arq);
fwrite(L->TITLE, sizeof(char), strlen(L->TITLE), arq);
fwrite(&c, sizeof(char), 1, arq); //writing delimiter
fwrite(L->AUTHOR, sizeof(char), strlen(L->AUTHOR), arq);
fwrite(&c, sizeof(char), 1, arq); //writing delimiter
fwrite(L->PUBLISHER, sizeof(char), strlen(L->PUBLISHER), arq);
fwrite(&c, sizeof(char), 1, arq); //writing delimiter
fwrite(L->YEAR, sizeof(int), 1, arq);
fwrite(&c, sizeof(char), 1, arq); //writing delimiter
fwrite(L->LANGUAGE, sizeof(char), strlen(L->LANGUAGE), arq);
fwrite(&c, sizeof(char), 1, arq); //writing delimiter
fwrite(L->PAGES, sizeof(int), 1, arq);
fwrite(&c, sizeof(char), 1, arq); //writing delimiter
fwrite(L->PRICE, sizeof(float), 1, arq);
fwrite(&c, sizeof(char), 1, arq); //writing delimiter
return;
}
The struct Book is declared like this:
typedef struct {
char *TITLE;
char *AUTHOR;
char *PUBLISHER;
int YEAR;
char *LANGUAGE;
int PAGES;
float PRICE;
} Book;
Main
int main() {
FILE *arq = fopen("BD_books2.bin", "rb+");
if(arq == NULL)
printf("Error while opening file!!!");
Book L;
readData(&L); //Reads all fields from keyboard and places in Book. Working properly
writeRegister(arq, &L);
system("pause");
return 0;
}
I have to use those pointers inside the struct, so I can't remove them. By the way, my problem is only with those integers and the float.
This fuction is only working properly if I write all the integers and floats (YEAR, PAGES and PRICE) with fprintf(), but I'm writing it in a binary file, and of course I want to write it in binary, so I'm trying to use fwrite().
Another thing is: the compiler is pointing incompatible type for argument 1 of 'fwrite' at this line: fwrite(L->PRICE, sizeof(float), 1, arq);
Can someone explain me what is happening? My program crashes when it tries to write in the file...

The first parameter of fwrite expects a pointer.
Lines such as the following:
fwrite(L->PAGES, sizeof(int), 1, arq);
Should be written as follows:
fwrite(&(L->PAGES), sizeof(int), 1, arq);
Sames goes for YEAR and PRICE members of that struct
fwrite(&(L->YEAR), sizeof(int), 1, arq);
...
fwrite(&(L->PRICE), sizeof(float), 1, arq);
Note, you don't need to make the same change for TITLE, PUBLISHER, and AUTHOR because the type of those member fields are already pointers (char*).

The signature of fwrite is
std::size_t fwrite( const void* buffer, std::size_t size, std::size_t count, std::FILE* stream );
The first argument to the function needs to be a pointer. I am surprised you didn't get compiler errors with the following lines.
fwrite(L->YEAR, sizeof(int), 1, arq);
fwrite(L->PAGES, sizeof(int), 1, arq);
fwrite(L->PRICE, sizeof(float), 1, arq);
They need to be
fwrite(&(L->YEAR), sizeof(int), 1, arq);
fwrite(&(L->PAGES), sizeof(int), 1, arq);
fwrite(&(L->PRICE), sizeof(float), 1, arq);
Also, it is a good practice to check the return values of all IO functions to make sure that they work as you expect them to.
if ( fwrite(&(L->YEAR), sizeof(int), 1, arq) != 1 )
{
// Deal with the error condition.
}

You must pass the address of L->YEAR to fwrite
fwrite(L->YEAR, sizeof(int), 1, arq);
fwrite(&(L->YEAR), sizeof(int), 1, arq);

the following code:
1) eliminates the bad practice of typedef'ing a struct
2) removed the mis-leading all caps of the struct field names
3) contains the needed #includes
4) contains the needed prototypes for the external (in another file) functions
5) checks for the worst of the many possible runtime errors
6) replaces the mis-leading 'L' with a meaningful name
7) modifies the file pointer variable to a commonly known name
suggest compiling with all warnings enabled (and fix the warnings)
for gcc, at a minimum, use '-Wall -Wextra -pednatic'
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Book
{
char *title;
char *author;
char *publisher;
int year;
char *language;
int pages;
float price;
};
int reglen( struct Book * );
int readData( struct Book * );
void writeRegister(FILE *fp, struct Book *myBook)
{ //writes in actual file position
char c = '|';
int sizeRegWrite = reglen(myBook); //reglen() returns the size of Book
fwrite(&sizeRegWrite, sizeof(int), 1, fp);
fwrite(myBook->title, sizeof(char), strlen(myBook->title), fp);
fwrite(&c, sizeof(char), 1, fp); //writing delimiter
fwrite(myBook->author, sizeof(char), strlen(myBook->author), fp);
fwrite(&c, sizeof(char), 1, fp); //writing delimiter
fwrite(myBook->publisher, sizeof(char), strlen(myBook->publisher), fp);
fwrite(&c, sizeof(char), 1, fp); //writing delimiter
fwrite(&(myBook->year), sizeof(int), 1, fp);
fwrite(&c, sizeof(char), 1, fp); //writing delimiter
fwrite(myBook->language, sizeof(char), strlen(myBook->language), fp);
fwrite(&c, sizeof(char), 1, fp); //writing delimiter
fwrite(&(myBook->pages), sizeof(int), 1, fp);
fwrite(&c, sizeof(char), 1, fp); //writing delimiter
fwrite(&(myBook->price), sizeof(float), 1, fp);
fwrite(&c, sizeof(char), 1, fp); //writing delimiter
return;
} // end function: writeRegister
int main( void )
{
FILE *fp = fopen("BD_books2.bin", "rb");
if(fp == NULL)
{
perror( "fopen for BD_books2.bin failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
struct Book myBook;
int goodRead = readData(&myBook); //Reads all fields from keyboard and places in Book. Working properly
if( goodRead )
{
writeRegister(fp, &myBook);
}
system("pause");
return 0;
} // end function: main

Related

C - Add an array of integers in a binary file

I have to add an array of int passed as parameter in a binary file as argument of the function. In parameter of the function there is also the size of the array.
If the file is empty we write the array but if the file already contains an array, we concatenate the two arrays.
My concern is that at each execution, I am reported a crash.
Here is my code:
void appendIntArray(char* filename, int* array, int N){
int* buffer = (int*) malloc(sizeof(int)*200);
FILE* fp;
if(fp == NULL) {
return(N);
}
fp = fopen(filename, "rb");
fread(N, sizeof(int), 1, fp);
fread(buffer, sizeof(int), N, fp);
fclose(fp);
fp = fopen(filename, "wb");
fwrite(&N, sizeof(int), 1, fp);
fwrite(buffer, sizeof(int), 1, fp);
fwrite(array, sizeof(int), N, fp);
fclose(fp);
return(N, buffer,array);
}
`
Could someone please tell me why my program crashes and correct me.
If the file is empty we should have an array. If the file already contains an array, I should have two arrays concatenated.
Before allocating the buffer, read the current length from the file. Add N to that to get the size of the final resulting array, and use that in malloc(). Then you can use memcpy() to copy the new array to the end of the buffer after the old file contents.
To return the new N to the caller, pass this parameter as a pointer.
You need to call fopen() before you check if fp is null.
To return the new array of file contents, you have to declare the function to return int *, not void.
char *appendIntArray(char* filename, int* array, int *N){
FILE* fp = fopen(filename, 'rb');
if(!fp) {
return NULL;
}
int currentsize;
fread(&currentsize, sizeof(int), 1, fp);
int* buffer = (int*) malloc(sizeof(int)*(currentsize + *N));
if (!buffer) {
return array;
}
fread(buffer, sizeof(int), currentsize, fp);
fclose(fp);
fp = fopen(filename, "wb");
if (!fp) {
return NULL;
}
memcpy(&buffer[currentsize], array, N * sizeof(int));
*N += currentsize;
fwrite(N, sizeof(int), 1, fp);
fwrite(buffer, sizeof(int), *N, fp);
fclose(fp);
return buffer;
}

I want to save quantized int8 weights from a convolutional neural network, are my code edits in c correct?

Here is a post I made on the GitHub page: https://github.com/AlexeyAB/darknet/issues/1405#issuecomment-927394677
Here is all the source code: https://github.com/AlexeyAB/yolo2_light/tree/781983eb4186d83e473c570818e17b0110a309da/src
The closing bracket mistake is easy to fix. I noticed that I got outputs when I added an & to the multipliers. Is & the correct pointer for structs? I put the function in additionally.c, referenced it in additionally.h, and officially referenced it in main.c.
void save_weights_int8(network net, char *filename, int cutoff)
{
fprintf(stderr, "Saving weights to %s\n", filename);
FILE *fp = fopen(filename, "wb");
if(!fp) file_error(filename);
int major = 0;
int minor = 1;
int revision = 0;
fwrite(&major, sizeof(int), 1, fp);
fwrite(&minor, sizeof(int), 1, fp);
fwrite(&revision, sizeof(int), 1, fp);
fwrite(net.seen, sizeof(int), 1, fp);
int i;
for(i = 0; i < net.n && i < cutoff; ++i){
layer l = net.layers[i];
if(l.type == CONVOLUTIONAL){
//save_convolutional_weights(l, fp);
int num = l.n*l.c*l.size*l.size;
fwrite(l.biases, sizeof(float), l.n, fp);
fwrite(l.weights_int8, sizeof(uint8_t), num, fp);
fwrite(&l.weights_quant_multipler, sizeof(float), 1, fp);
fwrite(&l.input_quant_multipler, sizeof(float), 1, fp);
}
}
fclose(fp);
}

Misunderstanding of binary file writing/reading in C

Can someone please explain why the following code segfaults whenever I attempt to do anything with either of the character arrays inside of the struct after I read it in from the binary file? The code is as follows:
struct my_struct {
int filename_len;
char *filename;
int size;
char *contents;
};
int main() {
FILE *fp = fopen("test.bin", "wb");
char *one = "list1";
char *two = "test file";
int one_len = strlen(one);
int two_len = strlen(two);
fwrite(&one_len, sizeof(int), 1, fp);
fwrite(&one, one_len, 1, fp);
fwrite(&two_len, sizeof(int), 1, fp);
fwrite(&two, two_len, 1, fp);
fclose(fp);
struct x *temp = malloc(sizeof(struct x));
fp = fopen("test.bin", "rb");
fread(&(temp->filename_len), sizeof(int), 1, fp);
fread(&(temp->filename), sizeof(char), temp->filename_len, fp);
fread(&(temp->size), sizeof(int), 1, fp);
fread(&(temp->contents), sizeof(char), temp->size, fp);
// This does not segfault
printf("%d\n", temp->filename_len);
// This does
printf("%s\n", temp->filename);
fclose(fp);
return 0;
}
Thank you!
fwrite(&one, one_len, 1, fp);
&one is the address of the pointer one on the stack, not the location it points to. This means that, instead of writing the string pointed to by one, you're writing the bytes that make up its address, potentially along with whatever happens to come after that in memory.
fread(&(temp->filename), sizeof(char), temp->filename_len, fp);
Similarly, this reads a pointer (or part of a pointer) into temp->filename, and may additionally overwrite whatever happens to be after it.
What you need to do is:
fwrite(one, one_len, 1, fp);
Write the actual contents of the string, not its address.
temp->filename = calloc(temp->filename_len + 1, sizeof(char));
fread(temp->filename, sizeof(char), temp->filename_len, fp);
Allocate a buffer sized appropriately for the filename, then read data into that buffer.
1) You are calling fread with the address of temp->filename.
fread(&(temp->filename), sizeof(char), temp->filename_len, fp)
You don't want to do this. temp->filename is already a pointer to a char. Instead pass simply temp->filename.
2) You aren't allocating any space for temp->filename. You need to do this after you read temp->filename_len.
fread(&(temp->filename_len), sizeof(int), 1, fp);
temp->filename = malloc((temp->filename_len + 1) * sizeof(char))
fread(temp->filename, sizeof(char), temp->filename_len, fp);
temp->filename[temp->filename_len] = '\0';
Similarly for temp->contents

C i cant read binary file properly

Hello i have a structure with couple of variables and i try to write and read them from/to binary files but when i read them i see only strange symbols and i dont know what i messed up,i have tried couple of variants but none of them works
typedef struct catalog
{
char num[20];
char name[80];
char author[50];
double price;
int year;
char publisher[80];
} Catalog;
Catalog* createCatalogData()
{
Catalog* c = malloc(sizeof(*c));
if (!c)
{
// Ups... add error handling
exit(0);
}
printf("Add num ");
getString(&c->num);
printf("Add name ");
getString(&c->name);
printf("add author ");
getString(&c->author);
printf("Add price ");
if (scanf("%lf", &c->price) != 1)
{
// Ups... add error handling
exit(0);
}
printf("Add publisher");
getString(&c->publisher);
printf("Add year");
if (scanf("%d", &c->year) != 1)
{
// Ups... add error handling
exit(0);
}
char *filePath = malloc(strlen(c->num) + 13);
char *folderName = "Catalogs\\";
strcpy(filePath, folderName);
strcat(filePath, c->num);
strcat(filePath, ".bin");
FILE *file = fopen(filePath, "wb");
if (file == NULL)
{
printf("Error opening file!\n");
exit(1);
}
fwrite(&c->num,1, strlen(c->num), file);
fwrite(&c->name,1, strlen(c->name), file);
fwrite(&c->author,1, strlen(c->author), file);
fwrite(&c->price, 1, sizeof(double), file);
fwrite(&c->publisher,1, strlen(c->publisher), file);
fwrite(&c->year,1, sizeof(int), file);
fclose(file);
return c;
}
Catalog* readCatalogData(char *filePath)
{
Catalog* c = malloc(sizeof(*c));
FILE* fh;
fopen_s(&fh, filePath, "rb");
//check if file exists
char *ptr;
//read line by line
const size_t line_size = 300;
char* line = malloc(line_size);
int counter = 0;
char* date;
fread(c->num, 1, 21, fh);
fread(c->name, 1, 80, fh);
fread(c->author, 1, 50, fh);
fread(&c->price, 1, sizeof(double), fh);
fread(c->publisher, 1, 80, fh);
fread(c->year, 1, sizeof(int), fh);
return c;
}
When you do e.g.
fwrite(&c->num,1, strlen(c->num), file);
you write a variable number of bytes without any terminator. When you read the file you have no idea how many bytes to actually read.
The above fwrite call actually contains another error, in that you write a pointer and not the actual data in c->num.
Instead of writing the data members one by one, write the whole structure in one single call:
fwrite(c, sizeof c, 1, file);
And when reading the file read the whole structure in a single fread call.
Important note (and as noted by Attie in a comment): If you intend to make this portable, then you should use serialization to read and write the data, as the size of the structure might not be the same on all platforms.
For simple code and just "experimenting" then it will work fine.

Writing and printing strings from an array in a file in C

I have an array being written to the file, but then I need a way to print that same information out from the file when I call the function. The first part of the code is in the main function, and the second is a second function that prints out the values that are supposed to be from the file (fp).
fp = fopen("Grue.txt", "wb");
for(i = 0; i < 5; i++)
{
char newLine[3] = {"\n"};
char space[2] = {" "};
fwrite(array[i].name, strlen(array[i].name), sizeof(char), fp);
fwrite(space, strlen(space), sizeof(char), fp);
fwrite(array[i].height, strlen(array[i].height), sizeof(char), fp);
fwrite(space, strlen(space), sizeof(char), fp);
fwrite(array[i].weight, strlen(array[i].weight), sizeof(char), fp);
fwrite(space, strlen(space), sizeof(char), fp);
fwrite(array[i].items, strlen(array[i].items), sizeof(char), fp);
fwrite(newLine, strlen(newLine), sizeof(char), fp);
}
fclose(fp);
fp = fopen("Grue.txt", "rb");
PrintAGrue(fp);
void PrintAGrue(FILE *a)
{
// create End of file character onto the array being saved,
int i;
char n;
char h;
char w;
char m;
for (i=0; i<5; i++)
{
n = fread(a[i].name, strlen(array[i].name, sizeof(char), a);
h = fread(array[i].height, strlen(array[i].height, sizeof(char), a);
w = fread(array[i].weight, strlen(array[i].weight, sizeof(char), a);
m = fread(array[i].items, strlen(array[i].items, sizeof(char), a);
printf("This grue is called %s and is %s feet tall, and weighs %s pounds, and has eaten %s things.", n, h, w, m);
}
}
In PrintAGrue, it looks like you're using strlen() calls to decide how much data to read -- but how
can you know the size of the string before you've read it? (Also, the parentheses don't look balanced...)
Perhaps your file format should explicitly include a length field for each string -- then you
can do one fread to find the string size, and another to actually read the string.

Resources