why isn't fwrite overwriting my data in wb+? - c

I wrote a small program in C that creates a list of students in a binary file. I call function fsearch() (below) to search for a specified student and change his data, but the data seems not to be modified.
// the file is opened in mode "wb+"
int fsearch(FILE *f)
{
student s;
float matsearch;
printf("enter the matricule you want to find ");
scanf("%f",&matsearch);
rewind(f); // starting the search from the beginning
while(fread(&s,sizeof(student),1,f)==1 && s.mat!=matsearch);
if(s.mat==matsearch)
{
printf("we found what searched for\n");
printf("name: %s\n",s.fname);
printf("last name: %s\n",s.lname);
printf("matricule: %.f\n",s.mat);
fseek(f,-sizeof(student),SEEK_CUR);
student a;
scanf("%s",&(a.fname));
scanf("%s",&(a.lname));
scanf("%d",&(a.mat));
if(fwrite(&a,sizeof(student),1,f)==1)
{
printf("successfully wrote"); // this message does get printed
}
return(1); // successfully found
}
printf("we didn't find what you searched for\n");
return(0);
}

In addition to the one posted by bluesawdust, I found some other mistakes in the code:
// the file is opened in mode "wb+": this means that your file was destroyed on open (see here). You might want to use "rb+"
since you didn't initialize your student s structure (and no record was ever written in it because of my previous point) s.mat contains a random value
scanf("%d",&(a.mat));: as for printf, you should change the format string to "%f" (but actually you should use a string type, comparing floats with == is not good practice because of the roundings)

sizeof(student) is unsigned, so negating it is not appropriate here. You should cast it to an int before negating.

Related

Print the 10 best results of a txt file

I can't find a way to solve this one.
I have a text file like this : score.txt
pat 20
ananna 20
radis 19
The number of lines can be between 10 and anything.
My goal is to print the 10 line where the integers are the higher, in order.
I tried with this, but I can't even read the number in my text file.
void fillScore(){
FILE* f =NULL;
f= fopen("score.txt", "r");
char name[20];
int score,i,j,tmp;
int tabScore[10]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
char tabName[10][20];
if (f==NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
while(fscanf(f,"%s%d",name,&score)==1){
printf("TEST : %d - ",score);
for(i=0;i<10;i++){
if(score>tabScore[i]){
tmp=tabScore[i];
tabScore[i]=score;
for(j=i+1;j<10;j++){
score=tabScore[j];
tabScore[j]=tmp;
tmp=score;
}
}
}
}
for(i=0;i<10;i++){
printf("%d\n",tabScore[i]);
}
fclose(f);
}
Does anybody have a hint on this ? I can get how to do it. I know it's not a great question, because it shows a lack of research, but I swear that I search on the web for hours.
Thanks a lot.
You're testing fscanf against the wrong value 1.
As per man page,
on success, these functions return the number of input items successfully matched and assigned; this can be fewer than provided for, or even zero, in the event of an early matching failure
Since you're asking *scanf() to convert two items, you want to check its return value against 2.
The following works:
...
while(fscanf(f,"%s%d",name,&score) == 2){
...

search in a file in c

the data on the file.txt are placed as shown.
My Code is this:
int searchBookname()
{
FILE *myFile=fopen("file.txt","r+");
if (myFile!=NULL) // file exists
{
char tmp1[512];
char tmp2[512];
while(fgets(tmp1,512,myFile)!=EOF)
{
puts("Insert the Book Name: ");
scanf("%s",tmp2);
if(strstr(tmp1,tmp2)!=NULL){
printf("the book is found: %s\n\n",tmp1);
}else{
puts("\nSorry there was no Match with this name! Maybe Book is not recorded yet :(\n");
}
}
}else{ // file doesn't exist
puts("\nDatabase is not created yet. Please record a new book to create a simple database\n");
exit(0);
}
fclose(myFile); // closing the file
}
It keeps skipping the if statement 2 times for some reason and on the
3rd time it prints the correct result.
This happen for whatever book I try to search.
See here
How can I make it find the result without skipping the if statement.
You read the file line by line. So in the third loop/line there is a record with 'book1'. Code is working correctly as it is. Maybe you want to ask the user for a book name outside of the while loop and search in every line for the given book name. If there is, you can print you message and break from the loop.
int searchBookname()
{
FILE *myFile=fopen("file.txt","r+");
if (myFile != NULL) // file exists
{
char tmp1[512], tmp2[512];
puts("Insert the Book Name: ");
scanf("%s",tmp2);
// Skip the first two lines of the file
fgets(tmp1,512,myFile);
fgets(tmp1,512,myFile);
while(fgets(tmp1,512,myFile) != EOF)
{
if(strstr(tmp1,tmp2) != NULL)
{
printf("the book is found: %s\n\n",tmp1);
break;
}
else
{
puts("\nSorry there was no Match with this name! Maybe Book is not recorded yet :(\n");
}
}
}
else
{ // file doesn't exist
puts("\nDatabase is not created yet. Please record a new book to create a simple database\n");
exit(0);
}
fclose(myFile); // closing the file
}
It is obvious.
First 2 lines of file are following:
Record_Date ...
-> (empty line)
You are reading file line by line and check book name in each line. So if must fail for first 2 times.
If you want to find a book in your file, your approach is incorrect. There are different approaches for this, but simplest is reading book records into an structure array, and then look for book name in that array.

Troubles appending structure to file in C

I'm having some trouble to append a structure to a file:
OS: Ubuntu 14.04
Struct:
struct baris
{
char name[30];
char trusted[1];
int phone;
int id;
};
Func:
addNewBariga()
{
char answer[30];
struct baris new;
while(1){
printf("Enter new Barigas' ID please.");
scanf("%d",&new.id);
printf("Enter new Barigas' name please.\n");
scanf("%s",new.name);
printf("Enter new Barigas phone please. \n");
scanf("%d", &new.phone);
printf("Is Bariga trusted?\n\t[Y/N]:");
scanf("%s",new.trusted);
while(1)
{
if(strcmp(new.trusted,"Y") != 0 && strcmp(new.trusted,"y") != 0)
{
printf("%s",new.trusted);
printf("\nWrong command givven.\t\n[Y/N]:");
scanf("%s",&new.trusted);
}
else
break;
}
printf("Values you've entered:\n\tID:%d\n\tName: %s\n\tPhone: %d\n\tTrustworth:%s\nWould you like to proceed to saving?\n[Y/N]:\n",new.id,new.name,new.phone,new.trusted);
scanf("%s",&answer);
if(strcmp(answer,"Y") ==0 || strcmp(answer,"y")==0) //Process to saving
{
printf("saving...");
confPtr = fopen(filePath , "ab");
//fwrite(new.id, sizeof(new.id), 1, confPtr);
fwrite(&new, sizeof(struct baris), 1, confPtr);
fclose(confPtr);
break;
}
}
What I'm getting:
fabio\00\00\00\00\00\00\00\00\00fab\00\00\00\00\00\00\00\00\00fab\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00 <1\B5y\00\00\00\00\00\00\00fab\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00 \C5f\DAy\00\00\00\00\00\00\00
That output looks basically correct, what did you expect?
You're writing binary data to a binary file. Binary files are not very easy to inspect manually.
The first member of the structure, name, will always be 30 bytes long in the output for example.
Note as pointed out by #BLUEPIXY in a comment that this:
scanf("%s",new.trusted);
triggers undefined behavior if a non-zero length is entered, since trusted is only 1 character long that is consumed by the string terminator. You should increase its length, or (much better!) stop using direct scanf() like this and instead read a whole line of input with fgets() and parse it using sscanf().
Also, when using functions that can fail (like scanf(), sscanf() or fgets()) you must check the return values before relying on them to have succeeded.

C programming opening and reading from a file

int main(void){
FILE *ifp; //input file pointer
int totalClock; //total clock count
// BEGIN OPERATIONS=============================
ifp=fopen("prog1.asy.txt", "r");
system("PAUSE");
assert(ifp!=NULL);
//populate the instMem with inst===================
int i=0;
//system("PAUSE");
for (i=0;i<512;i++)
{
inst temp=parser(ifp);
if (temp.opcode==-1)
break;
instMem[i]=temp;
printf("%s\n", instMem[i].rawCode);
}
printf("\n%d instructions parsed\n", i-1);
system("PAUSE");// PAUSE TO CHECK CODE PARSING IS CORRECT========
int cont=0;
while (cont==0){
//begin sim================================================
//initialize the mem=======================================
int i;
for (i=0;i<512;i++)
data[i]=0;
for (i=0;i<32;i++)
reg[i]=0;
IF_Time=0;
ID_Time=0;
EX_Time=0;
MEM_Time=0;
WB_Time=0;
//prompt input parameters===================================
printf("Memory access time: c=");
scanf("%d", &c);
printf("\nMultiply time: m=");
scanf("%d", &m);
printf("\nExecute time: n=");
scanf("%d", &n);
assert(c>0);
assert(m>0);
assert(n>0);
//start execution now that the program has been broken to unparsed strings====
while (0==0)
{
WB();
MEM();
if (MEM_WB.instruction.opcode==HALT)
break;
EX();
ID();
IF();
totalClock++;
system("PAUSE");
}
//PRINT RESULTS=============================================
printf("Run again with new parameters? 0=yes");
scanf("%d", &cont);
}
fclose(ifp);
system("PAUSE");
return 0;
}
struct inst parser(FILE *ifp){
char str[100];
struct inst temp;
if (fgets(str, 100, ifp)==NULL) {
inst temp={"NULL", -1,0,0,0};
}
else {
inst temp={str, 0,0,0,0};
puts(str);
}
return temp;
}
I am trying to read in a test file so that i can parse it into strings for analysis later. It opens the test file but it doesn't read the lines of test in the code. Is there something I am doing wrong.
Your parser functions only reads once from the file and does nothing with the result (since temp would be a local variable to the if branch, not to the function). First thing is to remove inst from inst temp = ... to see that it reads the first instruction. Then, you need to make that function loop over all lines in the file.
First of all, you need to format your source code on this page to make it more readable.
For parser(), I don't think you can return a structure. So please use a pointer instead. And, as Mihai mentions, "temp" is a temporary variable located on the stack, and it will be destroyed when returning from function parser().
I don't see the declarations of variables in the code snippet:
IF_Time=0;
ID_Time=0;
EX_Time=0;
MEM_Time=0;
WB_Time=0;
So I assume you could remove some unused code to make the question clear.
The last thing is: to analyze log files, shell scripts is more suitable than C. If you're not working on a UNIX/Linux box, you could also use Perl/Python if you want. They are all less error prone and easy to debug when used to analyze log files.

Why does my program read an extra structure?

I'm making a small console-based rpg, to brush up on my programming skills.
I am using structures to store character data. Things like their HP, Strength, perhaps Inventory down the road. One of the key things I need to be able to do is load and save characters. Which means reading and saving structures.
Right now I'm just saving and loading a structure with first name and last name, and attempting to read it properly.
Here is my code for creating a character:
void createCharacter()
{
char namebuf[20];
printf("First Name:");
if (NULL != fgets(namebuf, 20, stdin))
{
char *nlptr = strchr(namebuf, '\n');
if (nlptr) *nlptr = '\0';
}
strcpy(party[nMember].fname,namebuf);
printf("Last Name:");
if (NULL != fgets(namebuf, 20, stdin))
{
char *nlptr = strchr(namebuf, '\n');
if (nlptr) *nlptr = '\0';
}
strcpy(party[nMember].lname,namebuf);
/*Character created, now save */
saveCharacter(party[nMember]);
printf("\n\n");
loadCharacter();
}
And here is the saveCharacter function:
void saveCharacter(character party)
{
FILE *fp;
fp = fopen("data","a");
fwrite(&party,sizeof(party),1,fp);
fclose(fp);
}
and the loadCharacter function
void loadCharacter()
{
FILE *fp;
character tempParty[50];
int loop = 0;
int count = 1;
int read = 2;
fp= fopen("data","r");
while(read != 0)
{
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
loop++;
count++;
}
fclose(fp);
}
So the expected result of the program is that I input a name and last name such as 'John Doe', and it gets appended to the data file. Then it is read in, maybe something like
1. Jane Doe
2. John Doe
and the program ends.
However, my output seems to add one more blank structure to the end.
1. Jane Doe
2. John Doe
3.
I'd like to know why this is. Keep in mind I'm reading the file until fread returns a 0 to signify it's hit the EOF.
Thanks :)
Change your loop:
while( fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp) )
{
// other stuff
}
Whenever you write file reading code ask yourself this question - "what happens if I read an empty file?"
You have an algorithmic problem in your loop, change it to:
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
while(read != 0)
{
//read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
loop++;
count++;
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
}
There are ways to ged rid of the double fread but first get it working and make sure you understand the flow.
Here:
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
You are not checking whether the read was successful (the return value of fread()).
while( 1==fread(&tempParty[loop],sizeof*tempParty,1,fp) )
{
/* do anything */
}
is the correct way.
use fopen("data","rb")
instead of fopen("data","r") which is equivalent to fopen("data","rt")
You've got the answer to your immediate question but it's worth pointing out that blindly writing and reading whole structures is not a good plan.
Structure layouts can and do change depending on the compiler you use, the version of that compiler and even with the exact compiler flags used. Any change here will break your ability to read files saved with a different version.
If you have ambitions of supporting multiple platforms issues like endianness also come into play.
And then there's what happens if you add elements to your structure in later versions ...
For robustness you need to think about defining your file format independently of your code and having your save and load functions handle serialising and de-serialising to and from this format.

Resources