Linear search for an element within structures saved to file - c

I have a module which searches through a file to find an index, and if it's found it is supposed to print the details relevant to that index. The program compiles and runs, but no matter if the patient is saved or not, it prints that the patient is not found. What's the logic error I'm missing?
note:patientCount is a global variable which is written to another file and updated every time a patient is added.
void patientSearch(struct patientRec patient[], struct apptRec appt[])
{
system("cls");
int c=0;
char search[6], admit;
printf("Enter the patient ID of the patient you would like to search for.\n");
scanf("%i", &search);
fflush(stdin);
FILE *fp;
fp=fopen("patients.txt", "r");
if(fp==NULL)
{
printf("\nError opening file!");
}
else
{
for (c=0; c<patientCount; c++)
{
if (search==patient[c].patientID)
{
printf("\nPatient found.\n\n");
printf("Patient ID: %i", patient[c].patientID);
fscanf(fp, "%s", patient[c].fName);
printf("\nPatient First Name: ");
puts(patient[c].fName);
fscanf(fp, "%s", patient[c].sName);
printf("\nPatient Surname: ");
puts(patient[c].sName);
fscanf(fp, "%i %c", patient[c].age, patient[c].sex);
printf("\nPatient Age: %i\nPatient Sex: %c", patient[c].age, patient[c].sex);
fscanf(fp, "%s", patient[c].notes);
printf("\n\nNotes: \n");
puts(patient[c].notes);
}
else
{
fscanf(fp, "\n");
}
}
}
fclose(fp);
if (c==patientCount)
{
printf("\nThis patient does not exist. Would you like to admit this patient?\n1: Yes\n2: No\n");
scanf(" %c", &admit);
if (admit=='1')
{
admitPatient(patient, appt);
}
}
}

char search[6], admit;
scanf("%i", &search);
if (search==patient[c].patientID)
Either change to
int search; // This allows the rest of the code to match
or change to
char search[6], admit; //Change the rest of the code to match
scanf("%s", &search);
if (strcmp(search, patient[c].patientID) == 0)
printf("Patient ID: %s", patient[c].patientID);
To make your input and compare in the same format.
Make sure that your search array is big enough to include the final '\0'

Related

How to update struct text file line by line

My code store all activities details in a file and I have problem accessing data in that file by searching using id. This is my add activities function and struct.
struct activities{
char id[5];
char actName[200];
char date[20];
char day[20];
}act;
//function to add volunteering activities
void addAct(){
FILE *fileAct;
//prompt user to enter activities details
printf("\n\t Planning Volunteering Activities");
printf("\n\t -----------------------------------");
printf("\n\t Program ID \t: ");
scanf(" %[^\n]%*c", &act.id);
printf("\t Name of Activity : ");
scanf(" %[^\n]%*c", &act.actName);
printf("\t Date \t\t: ");
scanf(" %[^\n]%*c", &act.date);
printf("\t Day \t\t: ");
scanf(" %[^\n]%*c", &act.day);
//create & write in file activity
fileAct = fopen("Activity", "a");
fprintf(fileAct, "\n\t %s \n", act.id);
fprintf(fileAct, "1. Name of Activity : %s \n", act.actName);
fprintf(fileAct, "2. Date : %s \n", act.date);
fprintf(fileAct, "3. Day : %s \n", act.day);
//close file activity
fclose(fileAct);
}
And this is my update function.
void updateAct(){
//variable declaration
char progID[5];
//open activity file
FILE *fp = fopen ("Activity", "r");
//prompt user to search activities to update
printf("\t Search by Program ID : ");
scanf(" %[^\n]%*c", &progID);
while( !feof(fp)){
fread (&act, sizeof(struct activities), 1, fp);
if (strcmp(progID, act.id) == 0)
printf("%s %s", act.id, act.actName);
}
fclose(fp);
}
In the update function above, I couldnt access the act.id in struct based on user search, instead, the program display the whole data in the file. How can fix this problem?
You provide pointers to char arrays, which technically is a pointer to a pointer. But scanf only needs pointers.
Remove the &'s of the scanf()-calls and add a maximum lengt specifier to your format arguments:
Change
scanf(" %[^\n]%*c", &progID);
to
scanf(" %4[^\n]%*c", progID);
for a 5 byte buffer.
void readLine(char* message, char* buffer, int buffer_size)
{
printf("\t%s: ", message);
fgets(buffer, buffer_size, stdin);
// fgets inserts '\n' at the end
// we are removing it
buffer[strlen(buffer) - 1] = '\0';
}
void addAct(){
FILE *fileAct;
struct activities newAct;
//prompt user to enter activities details
printf("\n\tPlanning Volunteering Activities");
printf("\n\t-----------------------------------\n");
readLine("Program ID", newAct.id, sizeof(newAct.id));
readLine("Name of Activity", newAct.actName, sizeof(newAct.actName));
readLine("Date", newAct.date, sizeof(newAct.date));
readLine("Day", newAct.day, sizeof(newAct.day));
//create & write in file activity
fileAct = fopen("Activity", "ab+");
if(NULL != fileAct) {
fwrite(&newAct, sizeof(struct activities), 1, fileAct);
//close file activity
fclose(fileAct);
}
}
void updateAct(){
//variable declaration
char progID[5];
struct activities readAct;
//open activity file
FILE *fp = fopen("Activity", "rb");
if(NULL != fp) {
//prompt user to search activities to update
printf("\tSearch by Program ID : ");
fgets(progID, sizeof(progID), stdin);
progID[strlen(progID) - 1] = '\0';
while(fread(&readAct, sizeof(struct activities), 1, fp) != 0){
if (strcmp(progID, readAct.id) == 0)
{
printf("%s %s\n", readAct.id, readAct.actName);
break;
}
}
fclose(fp);
}
}

How to delete a record when there's more than one record of the same name in C

I am working on code for s blood donation system. I'm currently struggling with the delete donor record function.
The delete record function is to delete the record of a donor with a given name. If there are two or more records with the same name in the file then the program asks for mobile number. While there may be more than one person with the same name, each person has a unique mobile number.
My problem is that when the same name is used for several records, the wrong record is deleted.
If there's only one record with that name, the program deletes the record in the manner that's required.
(The variable i is declared globally as int i)
Here's the delete function
void delete(struct blood *b,int n)
{
char name[50];
int phone;
int found=0;
int c=0;
FILE *fp = fopen("bloodrecord.txt", "r");
FILE *fp1 = fopen("temp.txt", "w");
printf("\nEnter Name: ");
scanf("%s", name);
printf("---------------------------------------------\n");
while(fread(&b[i],sizeof(struct blood),1,fp))
{
if(strcmpi(b[i].name,name)==0)
{
c=c+1;
printf("\nName: %s\n",b[i].name);
printf("Age: %d\n", b[i].age);
printf("Mobile no.: %d\n", b[i].phone);
printf("Blood group: %s\n", b[i].bg );
printf("Weight: %d\n", b[i].weight);
printf("Sex: %s\n",b[i].sex);
printf("Address: %s\n",b[i].add);
printf("\n");
if (c==1)
{
found=1;
}
else if(c>1)
{
printf("\nThere are more than one occurences of this name in the records\n");
printf("\nPlease enter the mobile number of the donor: ");
scanf("%d", &phone);
if (b[i].phone == phone)
{
found=1;
}
}
}
else
fwrite(&b[i],sizeof(struct blood),1,fp1);
}
fclose(fp);
fclose(fp1);
if (found==1)
{
fp1 = fopen("temp.txt", "r");
fp = fopen("bloodrecord.txt", "w");
while(fread(&b[i],sizeof(struct blood),1,fp1))
{
fwrite(&b[i],sizeof(struct blood),1,fp);
}
fclose(fp);
fclose(fp1);
}
else
{
printf("\n\aRECORD DOES NOT EXIST.\n");
}
printf("RECORD SUCCESSFULLY DELETED");
getchar();
getchar();
}
I suggest that to make the program simpler, you request both the donor's name and the donor's mobile number at the beginning.
Then you process the input file and look for both name and mobile number in a single pass.
I started with your code and made a few changes. See comments.
Please note that I have not tested this code nor compiled it. It should be essentially correct however there may be a compiler error if I made a syntax mistake.
I assume that the you are using the struct blood correctly in your code since you did not provide the code defining that struct.
I assume that an int is sufficiently large to hold the mobile number. Since the size of an int can vary and is determined by the compiler, it may or may not be large enough for a mobile number. See Range of values in C Int and Long 32 - 64 bits
One thing I do not understand is why you are using the b[i] syntax and where is the variable i defined? You could instead use a local variable in the delete() function.
I also have the delete() function returning a value indicating if it found a match or not. This may or may not be useful.
int delete()
{
struct blood b;
char name[50] = {0};
int phone;
int found = 0;
FILE *fp = fopen("bloodrecord.txt", "r");
FILE *fp1 = fopen("temp.txt", "w");
// Ask for the donor's mobile number along with their name
// at the beginning to make the search easier and be able to
// do this in a single pass.
printf("\nEnter Name of the donor: ");
scanf("%49s", name); // Oka's comments about scanf().
printf("\nPlease enter the mobile number of the donor: ");
scanf("%d", &phone);
printf("---------------------------------------------\n");
while(fread(&b, sizeof(struct blood), 1, fp))
{
// check both donor's name and donor's mobile number.
if(strcmpi(b.name, name) == 0 && b.phone == phone)
{
// print out the donor data and indicate we are deleting
// this donor record.
printf("Deleting donor record\n");
printf(" Name: %s\n", b.name);
printf(" Age: %d\n", b.age);
printf(" Mobile no.: %d\n", b.phone);
printf(" Blood group: %s\n", b.bg );
printf(" Weight: %d\n", b.weight);
printf(" Sex: %s\n", b.sex);
printf(" Address: %s\n", b.add);
printf("\n");
found = 1;
}
else {
// we are keeping this donor record so write it to the
// temp file.
fwrite(&b, sizeof(struct blood), 1, fp1);
}
}
fclose(fp);
fclose(fp1);
if (found == 1)
{
// file temp.txt has deleted donors so lets updated
// the original file, bloodrecord.txt, with the updated
// list of donors.
fp1 = fopen("temp.txt", "r");
fp = fopen("bloodrecord.txt", "w");
while(fread(&b, sizeof(struct blood), 1, fp1))
{
fwrite(&b, sizeof(struct blood), 1, fp);
}
fclose(fp);
fclose(fp1);
printf("RECORD SUCCESSFULLY DELETED");
}
else
{
printf("\n\aRECORD DOES NOT EXIST.\n");
}
getchar();
getchar();
return found; // indicate if we found a match or not.
}
I reused most of your code, and added a second pass to handle the actual delete (first pass searches for matching records).
void delete(struct blood *b,int n)
{
const int MOBILE_SIZE = 16;
char name[50];
int phone = 0;
int found=0;
int c=0;
FILE *fp = fopen("bloodrecord.txt", "r");
FILE *fp1 = fopen("temp.txt", "w");
printf("\nEnter Name: ");
scanf("%s", name);
printf("---------------------------------------------\n");
while(fread(&b[i],sizeof(struct blood),1,fp))
{
if(strcmpi(b[i].name,name)==0)
{
c=c+1;
printf("\nName: %s\n",b[i].name);
printf("Age: %d\n", b[i].age);
printf("Mobile no.: %d\n", b[i].phone);
printf("Blood group: %s\n", b[i].bg );
printf("Weight: %d\n", b[i].weight);
printf("Sex: %s\n",b[i].sex);
printf("Address: %s\n",b[i].add);
printf("\n");
found = 1;
}
}
/* Finished the first pass. Now, start again */
rewind(fp)
if (c > 1) {
printf("There are multiple records for the name %s\n", name);
printf("\nEnter Mobile Number: ");
scanf("%d", &phone);
}
while(fread(&b[i],sizeof(struct blood),1,fp))
{
if((c == 1 && strcmpi(b[i].name,name)==0)
|| (c > 1 && strcmpi(b[i].name,name) == 0 && b[i].mobile == mobile))
continue; /* skip this record */
}
else
fwrite(&b[i],sizeof(struct blood),1,fp1);
}
fclose(fp);
fclose(fp1);
if (found==1)
{
fp1 = fopen("temp.txt", "r");
fp = fopen("bloodrecord.txt", "w");
while(fread(&b[i],sizeof(struct blood),1,fp1))
{
fwrite(&b[i],sizeof(struct blood),1,fp);
}
fclose(fp);
fclose(fp1);
}
else
{
printf("\n\aRECORD DOES NOT EXIST.\n");
}
printf("RECORD SUCCESSFULLY DELETED");
getchar();
getchar();
}

Search and write data from one file to another

I need to write a C program to fetch data from one file and write it to another file, without using user defined functions. My requirements are to:
Search customer details by Name.
Store the transaction data (paid amount) in another text file.
I did the code to search by name. But its not working,
#include <stdio.h>
#include <stdlib.h>
int main () {
char name[10], nic[10], mobile[10];
char fname[10], fnic[10], fmobile[10];
char choice;
int amount;
FILE *cfptr;
printf("Enter search type - \n 1. NAME \n 2. NIC \n 3.MOBILE \n ----> ");
scanf("%c", &choice);
printf("Enter search text : ");
scanf("%s", &name);
cfptr = fopen ("customer.dat", "r");
while (!feof(cfptr)){
fscanf(cfptr, "%s %s %s", fname, fnic, fmobile);
printf("Read Name |%s|\n", fname );
printf("Read NIC |%s|\n", fnic );
printf("Read Mobile |%s|\n", fmobile );
}
fclose(cfptr);
scanf("%d", &amount);
return(0);
}
customer.dat File
Shan 100012 200202
Marsh 121213 667675
Kim 126573 663412
This code is not complete asI cant filter the single name assigning
if(name == fname)
as am getting
assignment to expression with array type error
Can any one complete me the code to search and save to another file so I can do the amount calculation part?
int Search_in_File(char *fname, char *str) {
FILE *fp;
int line_num = 1;
int find_result = 0;
char temp[512];
//gcc users
//if((fp = fopen(fname, "r")) == NULL) {
// return(-1);
//}
//Visual Studio users
if((fopen_s(&fp, fname, "r")) != NULL) {
return(-1);
}
while(fgets(temp, 512, fp) != NULL) {
if((strstr(temp, str)) != NULL) {
printf("A match found on line: %d\n", line_num);
printf("\n%s\n", temp);
find_result++;
}
line_num++;
}
if(find_result == 0) {
printf("\nSorry, couldn't find a match.\n");
}
//Close the file if still open.
if(fp) {
fclose(fp);
}
return(0);
}
few comments:
when scanning the choice, read it as an integer and not as a character.
scanf("%c", &choice); // change to scanf("%d", &choice);
single '=' is an assigment, you meant comparison which is double '=='
if(name = fname) // comparison is if(name == fname)
in order to compare string, do not use '==' operator. use strcmp or implement an equivalent of strcmp.
Thanks for the effort, As with changes, I have changed my code as below and its working. Without checking with the name, I alternately checked with the nic.
#include <stdio.h>
int main(void){
int nic, n, mobile;
char name[30];
FILE *aPtr;
aPtr = fopen("Details.txt","w");
if(aPtr == NULL){
printf("File cannot be opened");
return -1;
}
printf("Enter nic to search - ");
scanf("%d", &n);
fscanf(aPtr, "%d %-s %d", &nic, name, &mobile);
while(!feof(aPtr)){
if(nic == n){
Printf("%d %s %d \n", nic, name, mobile);
}
fscanf(aPtr, "%d %s %d", &nic, name, &mobile);
}
fclose(aPtr);
return 0;
}

What is wrong with the following code? I am trying to search for a record in a text file

The program runs fine till I create the file and enter records from structure, but when I try to search a record by using roll no, it crashes.
I am using a structure called student to store data and then I am creating a text file and then I use a for loop to write data on the text file. Then I reopen the file and try to search a record using student roll no.
Program runs fine until I try to search the student roll no. It crashes right after I enter the student roll no to be searched.
Can anyone tell me what modification is needed to make the search work?
Below is my code:
#include<stdio.h>
struct student {
int roll_no;
char name [80];
int age;
}st[30],s;
int main ()
{
int i,n;
char fname[80];
int search;
int found;
FILE *fp;
printf("\nEnter the file name : \n");
scanf("%s",fname);
fp=fopen(fname,"w");
if(fp==NULL)
{
printf("\nCannot create file :");
exit(0);
}
printf("\nNumber of students : \n");
scanf("%d",&n);
for(i=0;i<n;i++)
{
printf("\n\nInformation for student#%d : \n\n",i+1);
printf("\nStudent roll number : \n" );
scanf("%d",&st[i].roll_no);
printf("\nStudent name: \n: ");
scanf("%s",st[i].name);
printf("\nStudent age : ");
scanf("%d", &st[i].age);
}
fprintf(fp, "\nStudent roll no\t\t Student name\t\t student age\t\t\n\n");
for(i=0;i<n;i++)
{
fprintf(fp, "\n%d \t\t %s \t\t %d \t\t", st[i].roll_no,st[i].name,st[i].age);
}
fclose(fp);
fp=fopen(fname,"r+t");
if(fp==NULL)
{
printf("\nCannot open file\n");
exit(0);
}
printf("\n\nStudent roll no to be searched : ");
found=0;
scanf("%d", search);
while(!(feof(fp)) && (found==0))
{
fscanf(fp,"%d,%s,%d",&s.roll_no,s.name,&s.age);
if(s.roll_no==search)
{
fseek(fp,-sizeof(struct student), SEEK_CUR);
printf("\nEnter new name : \n");
scanf("%s", s.name);
fprintf(fp, "\n%d \t\t %s \t\t %d \t\t", s.roll_no,s.name,s.age);
found=1;
}
}
if(found=0)
{
printf("\nStudent record doesn't exist \n");
}
fclose(fp);
return 0;
}
In your code, you're missing an address-of operator in scanf(), thereby passing an invalid type of argument. Basically
scanf("%d", search);
should be
scanf("%d", &search);
That said, it is always a good practice to size-limit the inputs for string, like, for an array defined like char fname[80];, you should use
scanf("%79s",fname);
to avoid possible buffer overflow by excessively long input.
Also, always check for the return value of scanf() and family of functions to ensure their success.

Save, find and remove structure from txt file

I am studying IT and programming is something new for me. Last week I got a task to do. I have to write a program which can save a structure (personal data of company's workers) to file.txt. Program should be able to find a specific person (putting his name or surname) and delete all people whose got a surname given by user as well. These all tasks should be in separate functions. Till now I wrote this function:
void struktura()
{
struct Person
{
char name[30];
char surname[30];
int age;
int height;
int weight;
};
int ile;
int i = 0;
printf("\n");
printf("How many persons would you like add to database (max 10 at once): ");
scanf("%d", &ile);
printf("\n");
if (ile >= 0)
{
printf("You added no one.\n");
}
else
{
struct Person *osoba[10]; //
while (i < ile)
{
osoba[i] = (struct Person*) malloc(sizeof (struct Person));
printf("Give a name: ");
scanf("%s", osoba[i]->name);
printf("Give a surname: ");
scanf("%s", osoba[i]->surname);
printf("Age: ");
scanf("%d", &osoba[i]->age);
printf("Height: ");
scanf("%d", &osoba[i]->height);
printf("Weight: ");
scanf("%d", &osoba[i]->weight);
printf("\n");
i = i + 1;
}
printf("You have added: \n\n");
i = 0;
while (i < ile)
{
printf("%d) Name: %s, Surname: %s, Age: %d years, Height: %d cm, Weight: %d kg.\n", i + 1, osoba[i]->name, osoba[i]->surname, osoba[i]->age, osoba[i]->height, osoba[i]->weight);
i = i + 1;
}
for (i = 0; i < ile; i++)
{
free(osoba[i]);
}
}
}
In additition, I have a code which save these persons to the file.txt. I would like to separate code (below) to another function but I don't know how to pass a structure to function.
FILE *save;
char name[30];
printf("\nWhere to save a database: ");
scanf("%s", name);
save = fopen(name, "a");
if (save == NULL)
{
printf("This file doesn't exist!");
getchar();
exit(1);
}
i = 0;
while (i < ile)
{
fprintf(save, "Name: %s, Surname: %s, Age: %d years, Height: %d cm, Weight: %d kg.\n",osoba[i]->name, osoba[i]->surname, osoba[i]->age, osoba[i]->height, osoba[i]->weight);
i = i + 1;
}
fclose(save);
I wrote a function, which opens the whole content of file.txt as well. What I missing is : how to find a specific person and how to delete these persons(I was thinking about opening a second temporary file and copy an content of original file except these lines which include given name/surname) (all in separate functions). Do you have any ideas how I could do this? I was looking for it in some books but I couldn't find any help.
I would like to separate code (below) to another function but I don't
know how to pass a structure to function.
Define struct Person outside and above the functions, so it can be used in all of them. Then you can put the code which saves the persons to the file in a function
void save(int ile, struct Person *osoba[ile])
{
…
}
and call this with
save(ile, osoba);
how to find a specific person
You could use the following function, which is a little more complicated than necessary for the finding task, but can be reused for another purpose:
char prformat[] =
"Name: %s, Surname: %s, Age: %d years, Height: %d cm, Weight: %d kg.\n";
char scformat[] =
"Name: %[^,], Surname: %[^,], Age:%d years, Height:%d cm, Weight:%d kg.\n";
// Read the data file "file.txt", look for 'name' or 'surname' (unless NULL),
// and output line(s) to 'out' if or unless they match (depending on 'match')
scan(char *name, char *surname, _Bool match, FILE *out)
{
FILE *fp = fopen("file.txt", "r");
if (!fp) perror("file.txt"), exit(1);
struct Person osoba;
while (fscanf(fp, scformat, osoba.name, osoba.surname,
&osoba.age, &osoba.height, &osoba.weight) == 5
)
if ( name && strcmp(osoba. name, name) == 0 == match
|| surname && strcmp(osoba.surname, surname) == 0 == match
)
if (fprintf(out, prformat, osoba.name, osoba.surname,
osoba.age, osoba.height, osoba.weight)
< 0) perror(""), exit(1);
fclose(fp);
}
calling it with
char name[30];
printf("Give a name or surname to find: ");
if (scanf("%29s", name) == 1)
scan(name, name, 1, stdout); // print matching lines to stdout
delete all people whose got a surname given by user …
(I was thinking about opening a second temporary file and copy an content of original file except these lines …
You were thinking right:
printf("Give a surname to delete: ");
if (scanf("%29s", name) == 1)
{
FILE *fp = fopen("file.tmp", "w");
if (!fp) perror("file.tmp"), exit(1);
scan(NULL, name, 0, fp); // print non-matching lines to tempfile
if (fclose(fp) < 0) perror("file.tmp"), exit(1);
remove("file.txt");
if (rename("file.tmp", "file.txt") != 0) perror("file.tmp");
}

Resources