C - Add an array of integers in a binary file - c

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;
}

Related

Fwrite function cuts off data in output .tar file

I have a piece of code that is designed to replicate the creation of a .tar file albeit a simpler version of it. It will take in 2 .txt files and produce a .tar file of the 2 files. Below is my code for doing so. However when opening the .tar file it is corrupted and sure enough, by viewing the data in a hex editor the data is cut off.
#include<stdio.h>
#include<ctype.h>
#include<string.h>
#include<stdlib.h>
#define RECORDSIZE 512
#define NAMSIZ 100
#define TUNMLEN 32
#define TGNMLEN 32
struct header {
char name[NAMSIZ];//needed
char size[12];//needed
};
int main(int argc, char** argv) {
//argv[1] file1 argv[2] file2
char* file1 = argv[1];
char* file2 = argv[2];
FILE* f;
int lSize;
char temp_length[10];
char* file1_data, * file2_data;
int result;
//char* output_str = (char*)malloc(sizeof)
f = fopen(file1, "rb");
if (f == NULL) {
printf("File error!");
return 1;
}
fseek(f, 0, SEEK_END);
lSize = ftell(f);
fseek(f, 0, SEEK_SET);
file1_data = (char*)malloc(sizeof(char) * lSize);
if (file1_data == NULL) {
printf("Memory error!");
return 1;
}
result = fread(file1_data, 1, lSize, f);
file1_data[result] = '\0';
fclose(f);
sprintf(temp_length, "%d", lSize);
struct header* h1 = malloc(sizeof(struct header));
strcpy(h1->name, file1);
strcpy(h1->size, temp_length);
printf("Name:%s Value:%s\n", h1->name, h1->size);
printf("File 1 data:%s\n", file1_data);
f = fopen(file2, "rb");
if (f == NULL) {
printf("File error!");
return 1;
}
fseek(f, 0, SEEK_END);
lSize = ftell(f);
fseek(f, 0, SEEK_SET);
file2_data = (char*)malloc(sizeof(char) * lSize);
if (file2_data == NULL) {
printf("Memory error!");
return 1;
}
result = fread(file2_data, 1, lSize, f);
file2_data[result] = '\0';
fclose(f);
sprintf(temp_length, "%d", lSize);
struct header* h2 = malloc(sizeof(struct header));
strcpy(h2->name, file1);
strcpy(h2->size, temp_length);
printf("Name:%s Value:%s\n", h2->name, h2->size);
printf("File 2 data:%s\n", file2_data);
//allocate mem for output buffer
int total = sizeof(struct header) + sizeof(struct header) + sizeof(file1_data) + sizeof(file2_data);
printf("total length %d\n", total);
f = fopen("Result.tar", "wb");
//fwrite(input,length,no of ele,output buffer)
fwrite(h1, sizeof(struct header), 1, f);
fwrite(file1_data, sizeof(file1_data), 1, f);
fwrite(h2, sizeof(struct header), 1, f);
fwrite(file2_data, sizeof(file2_data), 1, f);
if (fwrite != 0)
printf("Contents to file written successfully !\n");
else
printf("Error writing file !\n");
fclose(f);
}
First file name: File1.txt
Data within:
This is File 1.
Second file name: File2.txt
Data within:
This is File 2.
File 2 has more data inside.
Decoded text output:
File1.txt�ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ31�ÍÍÍÍÍÍÍÍÍThis is File1.txt�ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ63�ÍÍÍÍÍÍÍÍÍThis is
As observed, File 2's name as well as the subsequent data has been cut off. I've been debugging but I'm unsure where am I going wrong as fwrite does not return a 0 hence, I'm assuming it's successful.
As the print statements are exactly what I expected, I don't think the reading of the data is the issue but rather the fwrite function. Hence I would like to seek advice on it.
The error resids in the way you calculate the total length. Indeed, you do not want to use sizeof(file1_data) as the length of the file. Instead you want to use the value returned when reading in result.
Create two variables file1_length and file2_length. Then populate them with the size of their respective file:
...
size_t f1_len, f2_len;
...
f = fopen(file1, "rb");
if (f == NULL) {
printf("File error!");
return 1;
}
fseek(f, 0, SEEK_END);
f1_size = ftell(f);
fseek(f, 0, SEEK_SET);
file1_data = (char*)malloc(sizeof(char) * f1_len);
...
int total = sizeof(struct header) + sizeof(struct header) + f1_len + f2_len;
...
fwrite(h1, sizeof(struct header), 1, f);
fwrite(file1_data, f1_len, 1, f);
fwrite(h2, sizeof(struct header), 1, f);
fwrite(file2_data, f2_len, 1, f);
...
Finally, use these variable as the length of the files' content.
NOTE: The value obtained by sizeof(file1_data) indicate the size of the type. Here, since file1_data is of type char * you get 4.

Save/Load function in C language

I am working on a game program that requires me to save a 2D array into a file, and then if the user wants to go back to that game then can load it back up and continue it. But I am having a problem with getting the array to save into a txt file. And for the load function, it is not being able to load anything. The user is supposed to select the load option and it should be able to call the txt file with the array and then allows them to continue playing the game.
This is my save function
void save(char *filename)
{
FILE *fp = fopen(filename, "wb");
fwrite(&size, sizeof(size), 1 , fp);
fwrite(board, sizeof(int), size, fp);
if(fp == NULL)
return;
fclose(fp);
}
This is my load function
void load(char *filename)
{
FILE *fp = fopen(filename, "rb");
fread(&size, sizeof(size), 1 , fp);
fread(board, sizeof(int), size, fp);
if(fp == NULL)
return;
fclose(fp);
}
Later in the code, I use a menu to call these functions.
Any help would be very appreciated!
board is not a 2D array, it's an array of pointers to rows. You need to loop over it, writing and reading each row separately.
Since the size of the board being loaded may be different from the board currently in memory, you need to free the old board and re-allocate the new one when loading.
void save(char *filename)
{
FILE *fp = fopen(filename, "wb");
if (!fp) {
perror("Can't open save file");
return;
}
fwrite(&size, sizeof(size), 1 , fp);
for (int i = 0; i < size; i++) {
fwrite(board[i], sizeof(*board[i]), size, fp);
}
fclose(fp);
}
void load(char *filename)
{
FILE *fp = fopen(filename, "r");
if (!fp) {
perror("Can't open save file");
return;
}
if (board) {
for (int i = 0; i < size; i++) {
free(board[i]);
}
free(board);
}
fread(&size, sizeof(size), 1 , fp);
board = malloc(size * sizeof(*board));
for (int i = 0; i < size; i++) {
board[i] = malloc(size * sizeof(*board[i]));
fread(board[i], sizeof(*board[i]), size, fp);
}
fclose(fp);
}
First of all, write RB while loading. Second, don't forget to close all of the files after entering the FILE command.
Additionally, I have advice for you: Always check if *fp is equal to NULL; it's great for debugging and can have huge impact on your code. You can also write a function for multiple checking while using file in your program.

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