#include <stdio.h>
typedef struct Forca // definining struct here
{
char palavra[TAM_PALAVRA];
char palavra_mascarada[TAM_PALAVRA];
int erros, acertos, tentativas;
} t_forca;
void salva_jogo(t_forca forca) //function that writes structure inside bin file
{
FILE* save;
save = fopen("save.bin", "w+b");
if (save == NULL)
{
printf("\nerro no arquivo\n");
}
fwrite(&forca, sizeof(forca), 1, save);
fclose(save);
}
void carrega_jogo(t_forca* forca) //function that read struct inside bin file
{
FILE* readsave;
readsave = fopen("save.bin", "r+b");
if (readsave == NULL)
{
printf("\nerro no arquivo\n");
} //printf error
fread(forca, sizeof(forca), 1, readsave);
fclose(readsave);
}
basically I'm trying to save and read a structure inside a binary file, and I'm quite lost cuz the file is being written but not read at all
In the function carrega_jogo, forca is a pointer, sizeof(forca) is the same as size of pointer, which is 4 or 8 bytes, depending on your system or compiler settings. The read function ends up reading only 4 or 8 bytes. The rest of the structure is likely uninitialized and leads to undefined behavior.
The correct version should be sizeof(t_forca)
Aside, for fwrite/fread it is enough "wb" and "rb".
Related
I have left some of the code out but it just involes opening the input file and then an If statement right after the comment "// Check if the bytes are JPEGs" ; but basically the program passes through all the necessary checks but fails the Valgrind check at the end. I have even rewatched the class and he uses free (variable that was malloc-ed) to free it; i tried swapping variables and everything but i still get an error.
int main(int argc, char *argv[])
{
int jpgs = 0; // Set an image counter for jpg names.
unsigned char jpgbuffer[512]; // Buffer to look through 512 bits.
FILE *images = NULL; // New file that is empty (used for jpg output).
char *jpg = malloc(sizeof(uint8_t)* sizeof(char)); // Allocate memory for the new file name for the images.
// Use the fread given in the hints.
while (fread(jpgbuffer, sizeof(char), sizeof(jpgbuffer), image) == sizeof(jpgbuffer))
{
// Check if the bytes are JPEGs.
{
// Copy everything after if the file IS a JPEG into a new file with name "00i".
sprintf(jpg, "%03i.jpg", jpgs);
// Open file in a write format.
images = fopen(jpg, "w");
// Incriment number of images.
jpgs++;
}
//
if (images != NULL)
{
fwrite(jpgbuffer, sizeof(char), sizeof(jpgbuffer), images);
}
}
free(jpg);
fclose(image);
fclose(images);
return 0;
}
In the following example, I am taking a struct that occupies 32 bytes in memory and writing that to a file and reading it back in -- i.e., serializing the data to a binary format:
#include <stdio.h>
typedef struct _Person {
char name[20];
int age;
double weight;
} Person;
int main(void)
{
Person tom = (Person) {.name="Tom", .age=20, .weight=125.0};
// write the struct to a binary file
FILE *fout = fopen("person.b", "wb");
fwrite(&tom, sizeof tom, 1, fout);
fclose(fout);
// read the binary data and set the person to that
Person unknown;
FILE *fin = fopen("person.b", "rb");
fread(&unknown, sizeof unknown, 1, fin);
fclose(fin);
// confirm all looks ok
printf("{name=%s, age=%d, weight=%f}", unknown.name, unknown.age, unknown.weight);
}
Note however that these are all values on the stack, and no pointers/indirection is involved. How might data be serialized to a file when, for example, multiple pointers can be involved, multiple variables may point to the same memory location, etc. Is this effectively what protocol buffers do?
Ok so you want a binary file. I used to do it this way long ago. It's fine. It just breaks when you move to another platform or bitness. I'm teaching the old way because it's a good place to start. Newer ways are popular now because they keep working when changing platforms or bitnesses.
When writing records to the file I would use structs like this:
typedef struct _Person {
char name[20];
int age;
double weight;
} Person;
typedef struct _Thing {
char name[20];
};
typedef struct _Owner {
int personId;
int thingId;
} Owner;
See how the Owner structure has Id members. These are just indices into the arrays of the other structures.
These can be written out to a file one after another, usually prefixed by a single integer written directly that says how many records of each kind. The reader just allocates an array of structs with malloc big enough to hold them. As we add more items in memory we resize the arrays with realloc. We can (and should) also mark for deleting (say by setting the first character of name to 0) and reusing the record later.
The writer looks something like this:
void writeall(FILE *h, Person *allPeople, int nPeople, Thing *allThings, int nThings, Owner *allOwners, int nOwners)
{
// Error checking omitted for brevity
fwrite(&nPeople, sizeof(nPeople), 1, h);
fwrite(allPeople, sizeof(*allPeople), nPeople, h);
fwrite(&nThings, sizeof(nThings), 1, h);
fwrite(allThings, sizeof(*allThings), nThings, h);
fwrite(&nOwners, sizeof(nOwners), 1, h);
fwrite(allOwners, sizeof(*allOwners), nOwners, h);
}
The reader in turn looks like this:
int writeall(FILE *h, Person **allPeople, int *nPeople, int *aPeople, Thing **allThings, int *nThings, int *aThings, Owner **allOwners, int *nOwners, int *aOwners)
{
*aPeople = 0; // Don't crash on bad read
*aThigns = 0;
*aOwners = 0;
*allPeople = NULL;
*allThings = NULL;
*allOwners = NULL;
if (1 != fread(nPeople, sizeof(*nPeople), 1, h)) return 0;
*allPeople = malloc(sizeof(**allPeople) * *nPeople);
if (!allPeople) return 0; // OOM
*aPeople = *nPeople;
if (*nPeople != fread(*allPeople, sizeof(**allPeople), nPeople, h)) return 0;
if (1 != fread(nThings, sizeof(*nThings), 1, h)) return 0;
*allThings = malloc(sizeof(**allThings) * *nThings);
if (!allThings) return 0; // OOM
*aThings = *nThings;
if (*nThings != fread(*allThings, sizeof(**allThings), nThings, h)) return 0;
if (1 != fread(nOwners, sizeof(*nOwners), 1, h)) return 0;
*allOwners = malloc(sizeof(**allOwners) * *nOwners);
if (!allOwners) return 0; // OOM
*aOwners = *nOwners;
if (*nOwners != fread(*allOwners, sizeof(**allOwners), nOwners, h)) return 0;
return 1;
}
There was an old technique for writing a heap arena directly to disk and reading it back again. I recommend never using it, and never storing pointers on disk. That way lies security nightmares.
When memory was cheap I would have talked about how to use block allocation and linked blocks to dynamically update the on-disk records partially; but now for problems you're going to encounter at this level I say don't bother, and just read the whole thing into RAM and write it back out again. Eventually you will learn databases, which handles that stuff for you.
So I have to write a program that prompts the user to enter the name of a file, using a pointer to an array created in main, and then open it. On a separate function I have to take a user defined string to a file opened in main and return the number of lines in the file based on how many strings it reads in a loop and returns that value to the caller.
So for my first function this is what I have.
void getFileName(char* array1[MAX_WIDTH])
{
FILE* data;
char userIn[MAX_WIDTH];
printf("Enter filename: ");
fgets(userIn, MAX_WIDTH, stdin);
userIn[strlen(userIn) - 1] = 0;
data = fopen(userIn, "r");
fclose(data);
return;
}
For my second function I have this.
int getLineCount(FILE* data, int max)
{
int i = 0;
char *array1[MAX_WIDTH];
if(data != NULL)
{
while(fgets(*array1, MAX_WIDTH, data) != NULL)
{
i+=1;
}
}
printf("%d", i);
return i;
}
And in my main I have this.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_WIDTH 144
void getFileName(char* array1[MAX_WIDTH]);
int getLineCount(FILE* data, int max);
int main(void)
{
char *array1[MAX_WIDTH];
FILE* data = fopen(*array1, "r");
int max;
getFileName(array1);
getLineCount(data, max);
return 0;
}
My text file is this.
larry snedden 123 mocking bird lane
sponge bob 321 bikini bottom beach
mary fleece 978 pasture road
hairy whodunit 456 get out of here now lane
My issue is that everytime I run this I keep getting a 0 in return and I don't think that's what I'm supposed to be getting back. Also, in my second function I have no idea why I need int max in there but my teacher send I needed it, so if anyone can explain that, that'd be great. I really don't know what I'm doing wrong. I'll appreciate any help I can get.
There were a number of issues with the posted code. I've fixed the problems with the code and left some comments describing what I did. I do think that this code could benefit by some restructuring and renaming (e.g. array1 doesn't tell you what the purpose of the variable is). The getLineCount() function is broken for lines that exceed MAX_WIDTH and ought to be rewritten to count actual lines, not just calls to fgets.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_WIDTH 144
/**
* Gets a handle to the FILE to be processed.
* - Renamed to indicate what the function does
* - removed unnecessary parameter, and added return of FILE*
* - removed the fclose() call
* - added rudimentary error handling.
**/
FILE *getFile()
{
char userIn[MAX_WIDTH+1];
printf("Enter filename: ");
fgets(userIn, MAX_WIDTH, stdin);
userIn[strlen(userIn) - 1] = 0; // chop off newline.
FILE *data = fopen(userIn, "r");
if (data == NULL) {
perror(userIn);
}
return data;
}
/**
* - removed the unnecessary 'max' parameter
* - removed null check of FILE *, since this is now checked elsewhere.
* - adjusted size of array1 for safety.
**/
int getLineCount(FILE* data)
{
int i = 0;
char array1[MAX_WIDTH+1];
while(fgets(array1, MAX_WIDTH, data) != NULL)
{
i+=1;
}
return i;
}
/**
* - removed unnecessary array1 variable
* - removed fopen of uninitialized char array.
* - added some rudimentary error handling.
*/
int main(void)
{
FILE *data = getFile();
if (data != NULL) {
int lc = getLineCount(data);
fclose(data);
printf("%d\n", lc);
return 0;
}
return 1;
}
There are several things I think you should repair at first:
getFileName should help you getting the file name (as the name says), so in that function you shouldn’t have both array1 and userIn (as a matter of fact array1 is not even used in the function, so it can be eliminated all togheter). The paramater and the file name should be ‘the same’.
data is a local FILE pointer, this means once you exit the function you lose it. My recommandation is to make it global, or pass it as an argument from the main class. Also do not close it 1 line after you open it.
I guess the getLineCount is fine, but usually is a good practice to return and printf in main what is returned.
That max that is passed to the second function maybe to help you with the max size of a line? it might be.
Summing up, your getFileName should return the file name, so that userIn is what should be given by that parameter. The File opening should be done IN THE MAIN FUNCTION and be closed after everything you do related to the file, so at the end. Also, open the file after you get the name of the file.
Hopefully it helps you! Keep us tuned with your progress.
The part of my code that I'm asking about looks like this.
My TXT is containing number from 1-20 divided by . I want to make a BINARY file
from this txt, that's what the program supposed to do, but it is only feeling it up with memory dirt. Can you tell me if my code has mistakes.
void txt_to_bin (void)
{
FILE *ft,*fb;
int a;
ft = fopen("binadatok.txt","rt");
fb = fopen("versenyazonosito.dat","wb");
while (fscanf(ft,"%d\n",&a) != EOF)
{
fprintf(fb,"%d\n");
}
}
You need to use fwrite when writing to a binary file, not fprintf:
fwrite(&a, sizeof(a), 1, fb);
you are not providing any value in fprintf(fb,"%d\n") you should provide input of a in this statement .
void txt_to_bin (void)
{
FILE *ft,*fb;
int a;
ft = fopen("binadatok.txt","rt");
fb = fopen("versenyazonosito.dat","wb");
while (fscanf(ft,"%d\n",&a) != EOF)
{
fprintf(fb,"%d\n",a);
}
}
now it will work.
I have the code below which compiles fine in xcode, but when I take it across to Microsoft Visual studio I get a bunch of errors.
void openfile(int mapArray[MAX_HEIGHT][MAX_WIDTH], int *interest, int *dimension1, int *dimension2)
{
int counter = 0;
char buffer;
int rowss, colss;
*interest = 0;
FILE *f;
f = fopen(FILENAME, "r");
if (f==NULL) {
printf("Map file could not be opened");
return 0;
}
// create char array the dimensions of the map
fscanf(f, "%d %d" , dimension1, dimension2 );
// printf("%d %d\n" , dimensions[0], dimensions[1]);
// Reads the spaces at the end of the line till the map starts
buffer=fgetc(f);
while (buffer!='*') {
buffer=fgetc(f);
}
// Read the txt file and print it out while storing it in a char array
while (buffer!=EOF) {
mapArray[rowss][colss]=buffer;
colss++;
// Count up the points of interest
if (((buffer>64)&&(buffer<90))||(buffer=='#') ) {
counter++;
}
// resets column counter to zero after newline
if (buffer=='\n') {
colss=0;
rowss++;
}
buffer=fgetc(f);
}
// Closes the file
fclose(f);
*interest=counter;
}
Which parts are creating all the errors?
I get this list of errors when attempting to compile
Thanks in advance.
I see a few immediate problems. First, you're not initialising rowss or colss before you use them, hence they could contain any value.
Second, fgetc() returns an int so that you can detect end of file. By using a char to hold the return value, you're breaking the contract with the standard library.
Thirdly, you return a 0 if the filename couldn't be opened, despite the fact that the function is specified to return void (ie, nothing).
No doubt those are three of the errors the compiler picked up on, there may be others, and you should probably post the error list with your question for a more exhaustive analysis.