Reputation: 512
I am trying to open a binary file read a part from it and then modify it but this ends up in an infinite loop.
Things I had in mind before writing the program:
The code below is one of my many approaches with no success:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stoixeia
{
char e[30];
char t[5];
float mo;
int ilikia;
};
int main(void)
{
FILE *fptr;
struct stoixeia st;
int c;
if((fptr = fopen("sxoleio","rb+")) == NULL)
exit(1);
while((c = fread(&st,sizeof(struct stoixeia),1,fptr)) != EOF)
{
fseek(fptr,-44,SEEK_CUR);
for(int i = 0; i < strlen(st.e); i++)
st.e[i] += 1;
fwrite(&st,sizeof(struct stoixeia),1,fptr);
}
fclose(fptr);
return 0;
Other unsuccessful approaches:(feof,check for eof inside the loop etc.)
The only success I had so far was with the code below:
while((c = fgetc(fptr)) != EOF)
{
fseek(fptr,-1,SEEK_CUR);
fread(&st,sizeof(struct stoixeia),1,fptr);
fseek(fptr,-44,SEEK_CUR);
for(int i = 0; i < strlen(st.e); i++)
st.e[i] += 1;
fwrite(&st,sizeof(struct stoixeia),1,fptr);
fseek(fptr,1,SEEK_CUR);
fseek(fptr,-1,SEEK_CUR);
}
fclose(fptr);
Using fgetc() as the while condition and moving indicator by one byte to the right after the operations and then moving it back by one byte seems to trigger EOF and the program ends with success.
What is the reason for this behavior?
I really want to understand the behavior for this so anything would be much appreciated.
Thanks in advance.
Upvotes: 0
Views: 261
Reputation: 212634
There are a few issues with your code, but I think the biggest misconception is the return value of fread
. Its return value should not be compared to EOF. When you reach end of file, fread
will return a short count. In this case, that means it will return zero. Try:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stoixeia {
char e[30];
char t[5];
float mo;
int ilikia;
};
static void die(const char *msg) { perror(msg); exit(EXIT_FAILURE); }
int
main(int argc, char **argv)
{
FILE *fptr;
struct stoixeia st;
size_t c;
const char *path = argc > 1 ? argv[1] : "sxoleio";
if( (fptr = fopen(path, "rb+")) == NULL ){
die(path);
}
while( (c = fread(&st, sizeof st, 1, fptr)) == 1 ){
if( fseek(fptr, -sizeof st, SEEK_CUR) == -1 ){
die("fseek");
}
for( size_t i = 0; st.e[i] && i < sizeof st.e; i++ ){
st.e[i] += 1;
}
if( fwrite(&st, sizeof st, 1, fptr) != 1 ){
die("fwrite");
};
}
if( fclose(fptr) ){
die("fclose");
}
return EXIT_SUCCESS;
}
But, it's probably cleaner to skip the seeks completely and use two different file handles. Something like:
if( (rf = fopen(path, "r")) == NULL) {
die(path);
}
if( (wf = fopen(path, "r+")) == NULL) {
die(path);
}
while( (c = fread(&st, sizeof st, 1, rf)) == 1) {
for( size_t i = 0; st.e[i] && i < sizeof st.e; i++ ){
st.e[i] += 1;
}
if( fwrite(&st, sizeof st, 1, wf) != 1 ){
die("fwrite");
};
}
Upvotes: 1