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.
Related
char arrTypeLabels[3][7]= {{"Random"},{"ASC"},{"DESC"}};
FILE *f;
f= fopen( "TIMES.txt", "wb");
if (f == NULL)
{
printf("Error! Could not open file\n");
exit(-1);
}
int i,j;
for(i=0;i<3;i++)
{
for(j=0;j<7;j++)
{
printf("%c",arrTypeLabels[i][j]);
fwrite(arrTypeLabels[i][j],sizeof(char),sizeof(arrTypeLabels),f);
}
}
fclose(f);aenter code here
Im opening the TIMES.txt file but i cant see any output, althought i think my code is right .......................... :/ pls help...
char arrTypeLabels[3][7] = {
{"Random"},
{"ASC"},
{"DESC"}
};
FILE *f = fopen("TIMES.txt", "wb"); //wb is OK
if (f == NULL)
{
printf("Error! Could not open file\n");
exit(-1);
}
int i, j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 7; j++)
{
printf("%c", arrTypeLabels[i][j]);
fwrite(arrTypeLabels[i] + j, sizeof (char), sizeof (char), f); //your mistake is here
}
}
fclose(f);
I don't know how you're even able to copile your code, because in fwrite, the first argument needs to be a pointer, or in your code, you're giving the value.
Also, what you're trying to do is confusing, because it looks like you're trying to write char by char, but you're attempting to write the whole data contained in arrTypeLabels in one fwrite call.
If you just want to write that array to a file, you can make something like :
char arrTypeLabels[3][7]= {{"Random"},{"ASC"},{"DESC"}};
FILE *f;
f= fopen( "TIMES.txt", "wb");
if (f == NULL)
{
printf("Error! Could not open file\n");
exit(-1);
}
fwrite(arrTypeLabels,sizeof(char),sizeof(arrTypeLabels),f);
fclose(f);
or something like :
char arrTypeLabels[3][7]= {{"Random"},{"ASC"},{"DESC"}};
FILE *f;
f= fopen( "TIMES.txt", "wb");
if (f == NULL)
{
printf("Error! Could not open file\n");
exit(-1);
}
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 7; j++)
fwrite(arrTypeLabels[i] + j,sizeof(char),sizeof(char),f);
}
fclose(f);
note that the first method is much faster since you don't have to write (to a file i.e into the hard drive) every single character one at a time.
fwrite first and third parameters are wrong. Since you want to write char by char, your line should be fwrite(&buf[i][j], 1,1,f);
Or simplier, use fputc:
fputc(buf[i][j], f);
The objective is to append entries to a json file. Here is a demo program similar to my application. When I run the below code, after appending 1020 entries, the append stops.
#include <stdio.h>
#include <string.h>
#define ENTRIES_PER_LOG 10000
static int packet_count = 0;
static char filename[100] = "output.json";
int write_json(const char *json){
packet_count++;
// create file if it doesn't exist
FILE* fp = fopen(filename, "r");
if (!fp)
{
fp = fopen(filename, "w");
if (!fp)
return 0;
fputs("[]", fp);
fclose(fp);
}
// add the document to the file
fp = fopen(filename, "rb+");
if (fp)
{
// check if first is [
fseek(fp, 0, SEEK_SET);
if (getc(fp) != '[')
{
fclose(fp);
return 0;
}
// is array empty?
int is_empty = 0;
if (getc(fp) == ']')
is_empty = 1;
// check if last is ]
fseek(fp, -1, SEEK_END);
if (getc(fp) != ']')
{
fclose(fp);
return 0;
}
// replace ] by ,
fseek(fp, -1, SEEK_END);
if (!is_empty)
fputc(',', fp);
// append the document
fputs(json, fp);
// close the array
fputc(']', fp);
fclose(fp);
return 1;
}
return 0;
}
int main(){
int i;
for(i = 0; i < 10000; i++){
char json[100] = "";
sprintf(json, "{\"a\":%d}", packet_count);
printf("%s\n", json);
write_json(json);
}
}
In each run, it stops after appending 1020 entries in the json file. But the program runs till the end of for loop. Restarting the process starts appending to the file, but again it appends only 1020 entries and then, it stops appending.I have no clue on why it stops. Any help or directions on why append stops after certain number of entries will be thankful.
Your program is leaking resources. That is each call to write_json is opening the file twice, while leaking the descriptor for the first open. After a certain amount of the calls it is reaching the limit of allowed opened files.
// create file if it doesn't exist
FILE* fp = fopen(filename, "r"); // <------ 1st open
if (!fp)
{
fp = fopen(filename, "w");
if (!fp)
return 0;
fputs("[]", fp);
fclose(fp);
}
// add the document to the file
fp = fopen(filename, "rb+"); // <------ Second open overwriting `fp`
I'm currently trying to use a CMP decompressor: https://web.archive.org/web/20070113004119/http://rewiki.regengedanken.de:80/wiki/.CMP
It does in fact decompress the cmp, but it does not write it into a file.
So i tried myself.
int main(int argc, char** argv)
{
int length, dstLength;
unsigned char* fileInMem; //compressed data
unsigned char* dstFile; //decompressed data
if (argc < 2) {
fprintf(stderr, "give filename.cmp as parameter\n");
return 1;
}
printf("%s", argv[1]);
fileInMem = loadFile(argv[1], &length); //compressed data read
if (fileInMem == NULL) {
return 1;
}
dstFile = parseCmp(fileInMem, length, &dstLength); //decompress and assign data to dstFile
if (dstFile) {
/* Now we can save the file from dstFile, dstLength bytes */
printf("%d bytes depacked\n", dstLength);
for (int i = 0; i < 16; i++) {
dataArray[i] = fileInMem[i];
}
FILE *writer = fopen(argv[2], "r+");
//fputs(fileInMem, writer);
//fputs(dstFile, writer);
fclose(writer);
free(dstFile);
}
free(fileInMem);
return 0;
}
As you can see the decompressed data is a pointer to an unsigned char (according to the website a bitstream) and I tried fputs() from stdio.h, but the resulting file contains only 4 Bytes when viewed in a hex-editor.
If you need more information, please comment.
Thank you in advance.
Edit: This is what I was able to change thanks to your help, but when I open the file, it is still empty:
FILE* writer = fopen(argv[2], "wb");
fwrite(dstFile, 192, 192, writer);
192, because the length of the first decompressed Image is 192 Bytes large.
This is a common issue.
First, you need to open the output file writer for writing in binary mode ("wb").
FILE *writer = fopen(argv[2], "wb");
Second, you can't use fputs to write arbitrary data to a file, since it expects a string. Use fwrite instead: (assuming writer is the output file, dstFile the decompressed data and dstLength the amount of bytes to write)
fwrite(dstFile, 1, dstLength, writer);
If you examine the resulting file with an hex editor, you will see it is identical to the decompressed data.
Test-update
I wrote some test-code to see what is wrong, share your results so we can help you.
Add these functions to your code:
void printDataToScreen(unsigned char *dataptr, int datalen)
{
if (dataptr == NULL)
{
printf("[!] ERROR, NULL POINTER PROVIDED!\n");
return;
}
printf("> Dumping %d bytes of data into the terminal...\n", datalen);
for (int i = 0; i < datalen; i++)
{
if (i % 16 == 0)
printf("\n ");
printf("%02X ", dataptr[i]);
}
printf("\n\n");
}
void writeDataToFile(char *fileName, unsigned char *dataptr, int datalen)
{
FILE *file = fopen(fileName, "wb");
if (dataptr == NULL)
{
printf("[!] ERROR, NULL POINTER PROVIDED!\n");
return;
} else if (file == NULL)
{
printf("[!] ERROR WHILE OPENING FILE '%s'!\n", fileName);
return;
}
printf("> Writting %d bytes of data to '%s'...\n", datalen, fileName);
int writtenBytes = fwrite(dataptr, 1, datalen, file);
printf(" Done, %d bytes written!\n\n", writtenBytes);
fclose(file);
}
void runTest(char *fileName, unsigned char *dataptr, int datalen)
{
printf("Running tests... [0/2 done]\n");
printDataToScreen(dataptr, datalen);
printf("Running tests... [1/2 done]\n");
writeDataToFile(fileName, dataptr, datalen);
printf("Finished! [2/2 done]\n");
}
Call it like this:
runTest(argv[2], dstFile, dstLength);
Add the call to this place in your code (comment this code, also the line where you close writer):
FILE *writer = fopen(argv[2], "r+");
//fputs(fileInMem, writer);
//fputs(dstFile, writer);
Please share your results.
I am trying to make a function that opens 2 files- one for reading and the other one for writing and then copies the first file into the other one binary and for some reason its just does not work. I was trying to debug the program few times but i could not recognize the problem.
void myCopyBinary(char * * argv) {
FILE * srcFile;
FILE * dstFile;
int yesNo = 0;
char temp = ' ';
int i = 0;
int size = 0;
char * buffer;
int resultFread = 0;
int resultFwrite = 0;
srcFile = fopen(argv[1], "rb");
if (srcFile != NULL) {
dstFile = fopen(argv[2], "rb");
if (dstFile != NULL) {
printf("Would you like to overwrite it? (Every Number -YES, 0-NO): ");
scanf("%d", & yesNo);
if (yesNo == 0) {
fclose(dstFile);
exit(0);
return 1;
}
}
dstFile = fopen(argv[2], "wb");
if (dstFile != NULL) {
fseek(srcFile, 0, SEEK_END); // non-portable
size = ftell(srcFile);
buffer = (char * ) malloc(sizeof(char) * size);
if (buffer == NULL) {
printf("Error with the buffer!\n");
exit(1);
}
do {
resultFread = fread(buffer, 1, sizeof(buffer), srcFile);
resultFwrite = fwrite(buffer, 1, resultFread, dstFile);
} while (resultFread > 0);
}
}
One a side note, before reopening the dstFile for writing you should close the previous descriptor.
Anyways, you called fseek(srcFile, 0, SEEK_END);, however you didn't seek back to the beginning, thus when you attempt to read you hit EOF. I guess this is the root of your problem, if not(or rather after fixing this it still doesn't work) then please give more details how it does not work.
I have a text file with numbers on each line. I want to write a function in C that reads in the file and returns the next number in the file every time the function is called.
For example if I have these numbers:
100
200
300
400
and a function called get_number(), if I call get_number() it will return 100, if I call it again, it will return 200, etc.
This is what I've written so far but every time the function is called, it always goes back to the first number in the text file.
int * get_number()
{
FILE* file = fopen("random_numbers.txt", "r");
char line[256];
if (file==NULL)
{
perror ("Error reading file");
}
else
{
fgets(line, sizeof(line), file);
printf("%s", line);
}
return 0;
}
here's a version that does exactly that :
int * get_number(long* pos)
{
FILE* file = fopen("random_numbers.txt", "r");
char line[256];
if (file==NULL)
{
perror ("Error reading file");
}
else
{
fseek(file , *pos , SEEK_CUR);
fgets(line, sizeof(line), file);
printf("%s", line);
}
*pos = ftell(file);
return 0;
}
and you call it from main like this
long pos = 0;
get_number(&pos);
or better yet use a static variable
int * get_number()
{
static long pos = 0;
FILE* file = fopen("random_numbers.txt", "r");
char line[256];
if (file==NULL)
{
perror ("Error reading file");
}
else
{
fseek(file , pos , SEEK_CUR);
fgets(line, sizeof(line), file);
printf("%s", line);
}
pos = ftell(file);
return 0;
}
It's a good idea to avoid opening a file repeatedly. Instead of opening the file every time you call the function, open it once, then pass a file pointer to the function each time you call it.
int * get_number(FILE *file)
{
char line[256];
fgets(line, sizeof(line), file);
printf("%s", line);
return 0;
}
int main()
{
FILE *file = fopen("random_numbers.txt", "r");
if (file == NULL)
{
perror("Error opening file");
return 1;
}
while (!feof(file))
{
get_number(file);
}
fclose(file);
}
Open the file in the calling function.
Pass the FILE* to get_number.
Return an int from get_number, not an int*.
Here's a modified get_number.
int get_number(FILE* file)
{
// This is the core functionality.
// You should add error handling code
int number;
int n = fscanf(file, "%d", &number);
if ( n != 1 )
{
// Add error handling code.
}
return number;
}
This is normal, because you open your file each time you call get_number(); (this is even worse because no fclose are called.
What you want maybe is giving a file descriptor at get_number(); in this way :
void get_number(FILE* file)
{
char line[256];
if (file==NULL)
perror ("Bad descriptor given");
else
{
if (fgets(line, sizeof(line), file) == NULL)
perror("Fgets failed");
else
printf("%s", line);
}
}
And what you want, outside your function, is to do the following :
FILE * file = fopen("random_numbers.txt", "r");
get_number(file); // 100
get_number(file); // 200
fclose(file);
I made your function void, because the return here is pointless. You could change that and use atoi and the return fonction.