search in a file in c - 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.

Related

save a file modified using a list (c language)

=============================================================
edit : im sorry it seems like i havent explained well
what my program does is
open file for reading => load list from the file => operations chosen by user will be applies to list (not file)(add-search-display-reset)\ => import change to file(in case there is any)
if the user chooses to only add an employee and quit will it be better to append the added node to the end of file, close and free list or its okay to open file for reading and overwrite all the nodes from the beggining
this last option will save me a lot of lines of code but will it save time and energy for the user while execution ?
=============================================================
i am workig on a (c language) school project where we have to use both lists and files to :
display a list of employees
add employees
search an employee
reset list
save and quit
so i am looking for the best way to do it, and as i know a good code is the one that ensures the program uses as less memory as it can and be as fast as it can.
what i am asking you is
after opening the file that contains the infos of employees and loadig it to the list, and modifying the list by add or reset, would it be better to :
open the file for "w" and fill it with the list.
or open it for "a+" to add from last employee.
note that this last way i will have to memorize the initial_number_of_lines (aka nodes) and look for the 'initial last node' to start loading from it.
note : the employee variables are first_name last_name and salary; VERIFY(file) returns 1 i file opened returns 0 if not;
void load_file(list *list, char *filename)
{
if (current_number_of_lines != initial_number_of_lines || list_reset == 1)
{
if (current_number_of_lines > initial_number_of_lines && list_reset == 0)
{
FILE *file = fopen(filename, "a+");
if (VERIFY(file) == 1)
{
for (int i = 0; i < initial_number_of_lines; i++)
{
list = list->next;
}
while (list != NULL)
{
fprintf(file, "%s\t%s\t%lf\n", list->emp.Fname, list->emp.Lname, list->emp.salary);
list = list->next;
}
}
fclose(file);
}
else if (list_reset == 1)
{
FILE *file = fopen(filename, "w");
while (list != NULL)
{
fprintf(file, "%s\t%s\t%lf\n", list->emp.Fname, list->emp.Lname, list->emp.salary);
list = list->next;
}
fclose(file);
}
else
printf("Error\n");
}
freeList(list);
}
If all your add operations adds the new node to the end of the list, you will get better performance using a+. On the other hand, the code will be more simple if you always rewrite the the whole file. So what is most important for you? Performance or simple code? I would start with the simple approach.
Some other notes.
It's pretty strange that you call the function load_file when it actually writes the file.
The variables: current_number_of_lines, initial_number_of_lines, list_reset seem to be global variables. Using global variables is something you should avoid.
The logic (aka if statements) seems too complicated. You can simply do:
void load_file(list *list, char *filename)
{
if (list_reset == 1)
{
...
}
else if (current_number_of_lines > initial_number_of_lines)
{
...
}
else if (current_number_of_lines < initial_number_of_lines)
{
printf("Error\n");
}
freeList(list);
}
If you use "w" to fopen() then it will truncate file to zero length or create text file for writing. The stream is positioned at the beginning of the file. You have to write all records to the file.
If you use "a+" to fopen() then the file will be open for reading and appending (writing at end of file). The file is created if it does not exist. Output is always appended to the end of the file. Warning: POSIX is silent on what the initial read position is when using this mode. In the mode, you will only write records that needs to be added.
Please also note that neither of the methods are well suited for sharing the data between two or more applications.
If new records are added at the end of the list, obviously it is faster to append those records ate the end of the file ("a+" mode).
Since you have a text file (made of text lines), it is unfortunately not possible to update the changed records. In that case, you must write everything from the list to the file ("w" mode).
If you change you file format in order to use a fixed size record then you can optimize the writing by positioning the file on the record and then write. For that, you'll define your record as a struct containing fixed size strings. And of course add an item in that struct to remember where it has been read from the list.

Search for word within file and display the title of the section containing the word?

I have to search for a word from a file containing multiple songs, separated by a specific string, and display every song title that contains the word in its lyrics.
The file has the following format:
xxxxxxxxxx
song title
Lyrics
xxxxxxxxxx
Song Title
Lyrics
[...]
The code I wrote is:
#include <stdio.h>
#include<string.h>
/* Note: pif will be function needed to search a word within a generic string */
int main(){
FILE *fp=fopen("file.txt", "r");
char line[200],search_string[]="xxxxxxxxxx",word[20],buff[200];
int cnt=0,flag=0;
gets(word);
if (!fp)
return -1;
printf("\n\tSongs Containing %s: ", word);
cnt=0;
while ( fgets ( line, 200, fp ) != NULL ) /*read a line*/
{
if(strstr(line,search_string)){ /*find the separator*/
fgets(line,200,fp);/*go ahead reading*/
strcpy(buff,line); /*save the title, which is the very next line after the separator*/
while(!strstr(line,search_string)){ /* while the lyrics do not match with another
separator go ahead reading*/
fgets(line,200,fp);
if(pif(line,word)) /*using the defined *pif* function (required), I'd find *word*
within the line */
flag=1;
}
if(flag)
printf("%s", buff);
}
}
fclose(fp);
return 1;
}
Is there anyway I can make this whole stuff working? The output displays each song titles instead of specific ones.
if(flag) printf("%s", buff); break; this should break after printing the very first song, but you're saying it's not.. so I think you've a typo in post..
now your code.. After you set your flag to 1 after you found a match, then you are not setting it back to zero even after printing the string. As your inner while iterates through the complete song, the print is done at the start of next song, where you should set flag=0; or else even if that word is not in the song, as flag remains 1, the song name is printed.
if(flag)
{
printf("%s", buff);
flag=0;
}
This should work.
note: all of this assumes your pif function is working properly.
Its just an issue of not resting your flag to 0 before your next check. Right now, every title that occurs after the first song that has the matching world will be printed. If your problem still persists it might have something to do with the pif function. Please do share if you do not get this right !!

Get specific info between two certain points in a text file using C

So i have this text file that contains what a person with certain email likes:
email1#gmail.com
Likes:
Animals
Sports
email2#gmail.com
Likes:
Science
Animals
What i really need are those specific words of what certain user email likes (only one email at the time choosen by scanf) and each liked topic of his (all of them are just one word) is going to be used in a function of my code (ex: function(Animals)).
Edit: I just want each word of what a email that i choose likes (Case email1 i want the word "Animals" and the word "Sports" extracted from the text file because i need to use those words). How can i do that with C?
Try the below code
#include<stdio.h>
#include<string.h>
int main()
{
FILE * fptr = NULL;
fptr = fopen("File.txt" , "r");//Let File.txt be the required file
if(fptr==NULL)//Check if file was opened successfully
{
printf("File could not be opened");
return 0;
}
printf("File opened\n");
char buff[1024];//To store line read from file
char email[1024];//To store email id
printf("Enter email id:");
scanf("%s",email);
int found=0;
while(fscanf(fptr,"%[^\n]\n",buff))//Read file line by line and store the line to buff
{
//printf(":%s:",buff);
if(strstr(buff,"#")!=NULL)//Set found=0 if the line in the file is an email id. Here I am checking for the word "#" in the line read since an email id will surely have an # symbol. Replace it with some checking function to verify if it's an email id
{
if(found==1)//If the email was already found break out of the loop
break;
found=0;
}
if(found==1)//If found=1 buff will have your required Likes including the word Likes:
{
if(strcmp("Likes:",buff)!=0)//If required word is not 'Likes:' since only the likes is required not the word 'Likes:'
{
printf("%s\n",buff);//buff contains the required like. It can be used as your functions argument.
}
}
if(strcasecmp(email,buff)==0)//Set found=1 if the required email is found
found=1;
if(feof(fptr))//Break out of the loop if file end is reached
break;
}
}
If email1 is the required email id, then your input should be email1#gmail.com as it is stored in this format in the file.

Having trouble making a simple settings file

Some backstory
I'm an engineering student (first year) and we had to create a program that could manage a list of students. Basically putting information of students in an array of structs (student name, birth date, grades). It had to be possible to add students, delete students, sort students, change information, add grades, save progress, load progress and generate a mark list(html/css).
My problem
I wanted to add settings to my project. I put some information in a file I called settings.txt. The first and second line are integers and can be 1 or 0. The third line is a string. Creating this file and reading from the file works fine, but of course I wanted the user to be able to change his settings too. However, when I run the code below, my .exe crashes. It's probably because of something stupid I'm doing but I've been looking at this for a couple of hours now and my 'fixes' make things worse. I hope someone can help me, thanks in advance! :)
I tried adding some comments in english, originally the outputs in printf were dutch. If anything is unclear, please ask!
Code
char getBool (char option[], char booly[]) {
if (option[0]!='0') {
strcpy(booly,"true");
} else {
strcpy(booly,"false");
}
}
char editSettings (char settings[], char startLoad[]) {
//This function will allow the user to edit some settings
//Declare variables: file: filename, lijn: storage for xth line of file,booly: true/false output. Settings:reset: 1/0,load: 1/0,startfile: filename
char file[15]="settings.txt",lijn[25],booly[10],reset,load,startfile[25];
int inp,i;
do {
i=1;
//Read file and output current settings to user
FILE * bestand;
bestand=fopen(file,"rt");
fgets(lijn,999,bestand);
while (!feof(bestand)) {
//i determines what line we're on -> There are always 3 lines
//1st line can be 0 or 1 -> Reset screen after cmd?
//2nd line can be 0 or 1 -> Load file
//3th line is a string (filename) -> .txt is automatically added when loading file
getBool(lijn,booly);
if (i==1) {
printf("%d - Reset screen after every command: %s\n",i,booly);
reset=lijn;
} else if (i==2) {
printf("%d - Load file on startup: %s\n",i,booly);
load=lijn;
} else if (i==3) {
strcpy(startfile,lijn);
}
fgets(lijn,999,bestand);
i++;
}
fclose(bestand);
printf("Pick a setting to change or enter 0 to cancel.\nChoose: ");
//Let user choose a value: 0, 1 or 2. Anything else won't
inp=inlezen("012");
printf("\n");
//Process users choice
if (inp=='1') {
//Toggle reset option, remain other options
bestand=fopen(file,"wt");
if (reset=='0') {
reset='1';
} else if(reset=='1') {
reset='0';
}
fprintf(bestand,"%s\n",reset);
fprintf(bestand,"%s\n",load);
fprintf(bestand,"%s\n",startfile);
fclose(bestand);
} else if (inp=='2') {
//Toggle load on startup option + read filename to start, remain reset option
bestand=fopen(file,"wt");
if (load=='0') {
load='1';
} else if(load=='1') {
load='0';
}
fprintf(bestand,"%c\n",reset);
fprintf(bestand,"%c\n",load);
if (load=='1') {
printf("\nWhich file must be loaded on startup?\nGive name: ");
scanf("%s",&startfile);
}
fprintf(bestand,"%s\n",startfile);
fclose(bestand);
}
} while (inp!='0');
printf("\n");
}
However, when I run the code below, my .exe crashes.
You define char …reset,load, and then you pass those characters to fprintf() with the wrong conversion specifier s:
fprintf(bestand,"%s\n",reset);
fprintf(bestand,"%s\n",load);
If your compiler didn't warn about inconsistent usage of those variables, you should use a better compiler; if it did, you should pay attention to the warnings.

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

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.

Resources