How to update struct text file line by line - c

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);
}
}

Related

When I try update an element in a line my file, the wrong element get updated in C. How access each element in a line in a file?

I am creating a task management system where the user can add,modify and delete their tasks. But I am facing errors with modifying elements in a line in a file.
This is where I add tasks to the file:
void add_task()
{
int id;
char name[50];
char category[50];
char info[50];
char date[20];
char status[20];
char another = 'Y';
FILE *fptr;
fptr = fopen("Tasks.txt","r+");
if (fptr==NULL)
{
printf("\nSYSTEM ERROR");
fptr = fopen("Tasks.txt","w");
getchar();
return;
}
while (another == 'Y'|| another == 'y')
{
fseek(fptr,0,SEEK_END);
printf("\nTo Add a new task enter the details below\n");
printf("Enter an ID to identify your tasks easily(LESS THAN 5 CHAR):");
scanf("%d",&id);
printf("Name of Task:");
getchar();
fgets(name,50,stdin);
name[strcspn (name, "\n")] = 0;
printf("Category of Task:");
fgets(category,50,stdin);
category[strcspn (category, "\n")] = 0;
printf("Information about task(Max 49 characters):");
fgets(info, 50, stdin);
info[strcspn (info, "\n")] = 0;
printf("Due Date of Task(yyyy/mm/dd):");
scanf(" %s", date);
printf("Status of Task\n TD = To-Do\n IP = In Progress\n CT = Completed Task\nEnter Status:");
scanf(" %s", status);
fprintf(fptr,"%d %s %s %s %s %s\n",id, name, category, info, date, status);
printf("\nDo you want to add another record (Y/N)");
fflush(stdin);
another = getchar();
}
fclose(fptr);
printf("\n\n\tPress any key to exit");
exit(0);
}
This is where I want to change only the category of the task but it changes the name instead:
void change_category()
{
int id;
char name[50];
char category[50];
char info[50];
char date[20];
char status[20];
int i;
FILE * fptr = fopen("Tasks.txt","r");
FILE * fp = fopen("temp.txt","w");
printf("Enter the ID of the task you want to update:");
scanf("%d",&id);
while(fscanf(fptr,"%d",&i) != EOF)
{
fscanf(fptr,"%s",category);
fgets(info,50,fptr);
if(i == id)
{
printf("Task Found");
printf("\nUpdating category for task with ID: %d",id);
printf("\nEnter new category:");
scanf("%s",category);
}
fprintf(fp,"%d %s %s\n",i,category,info);
}
fclose(fp);
fclose(fptr);
remove("Tasks.txt");
rename("temp.txt","Tasks.txt");
}
Sample entry into the file:
8291 Math Math HW Pg 1-2 2022/04/03 IP
Update Category entry:
English
Updated File:
8291 English Math HW Pg 1-2 2022/04/03 IP

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();
}

File Reading in C returns empty

I'm able to write data into a file but when I read it, it prints an empty file. I tried to make 2 programs one to write to file using permission "w" and one to read using "r" but when I combined both programs and changed permission to "w+" printing the files gives lots of empty spaces.
#include <stdio.h>
#include <stdlib.h>
void main()
{
char name[20];
char roll_no[15];
char class[10];
char semester[10];
char course[20];
FILE *file_pointer;
file_pointer = fopen("StudentRecords.txt", "w+");
if (file_pointer == NULL)
{
printf("\nError Opening File StudentRecords.txt\nCreate File Manually and Try Again.");
exit(1);
}
printf("\nENTER DETAILS FOR 5 STUDENTS\n");
//TAKE 5 RECORDS FROM USERS AND SAVE THEM IN FILE-
for (int i = 1; i <= 5; i++)
{
printf("\nStudent %d", i);
fprintf(file_pointer, "Student %d", i);
printf("\nName : ");
scanf("%s", &name);
fprintf(file_pointer, "\nName : %s", name);
printf("Roll No : ");
scanf("%s", &roll_no);
fprintf(file_pointer, "\nRoll No : %s", roll_no);
printf("Class : ");
scanf("%s", &class);
fprintf(file_pointer, "\nClass : %s", class);
printf("Semester : ");
scanf("%s", &semester);
fprintf(file_pointer, "\nSemester : %s", semester);
printf("Course : ");
scanf("%s", course);
fprintf(file_pointer, "\nCourse : %s", course);
printf("\n");
fprintf(file_pointer, "\n\n");
}
//READ ENTIRE FILE WORD BY WORD
char c;
c = fgetc(file_pointer);
while (c != EOF)
{
printf("%c", c);
c = fgetc(file_pointer);
}
fclose(file_pointer);
}
When you write/read in a file you use a stream (FILE*) that stores where in the file you are (position).
When you finished writting that was the last stream position.
You need to go back to the begin of the file if you want to read it entirely.
You can use fseek for this.
int fseek(FILE *stream, long int offset, int whence);
1 SEEK_SET : Beginning of file
2 SEEK_CUR : Current position of the file pointer
3 SEEK_END : End of file
...
//READ ENTIRE FILE WORD BY WORD
char c;
fseek(file_pointer, 0, SEEK_SET);
c = fgetc(file_pointer);
while (c != EOF)
{
printf("%c", c);
c = fgetc(file_pointer);
}
For the read section do this instead. This will reset the position indicator to the beginning of the file so you can read from the beginning.
if ( fseek(file_pointer, 0L, SEEK_SET) == 0 ) {
char c;
c = fgetc(file_pointer);
while (c != EOF)
{
printf("%c", c);
c = fgetc(file_pointer);
}
}

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;
}

Program is not reading some characters from first line of text file

So my program basically asks for the assignment name/student name after clicking "1" from the student menu to submit an assignment. The function reads an arbitrary assignment from a text file I have in my debug folder, called "myassignment.txt". Then it creates a new file called "submission.txt" with the assignment name, student name and the assignment in it.
When I click "2" from the student menu to see the submitted assignment, it prints the assignment name and student name fine, but skips the first few characters from the first line of the actual assignment.
It skips more or less characters depending on how long the assignment name and student name are.
I can't figure out why it's doing this.
Here is my code for the data structure, menu, and functions used in the first two options of the menu:
#include "assignmentgrading3.h"
#define MAX_STUDENT_NAME_SIZE 50
#define MAX_ASSIGNMENT_NAME_SIZE 50
#define MAX_ASSIGNMENT_SIZE 1000
typedef struct{
char assignmentName[MAX_ASSIGNMENT_NAME_SIZE];
char studentName[MAX_STUDENT_NAME_SIZE];
char assignment[MAX_ASSIGNMENT_SIZE];
double score;
} Assignment;
void studentMenu(Assignment* assignmentStruct) {
int choice;
do {
printf("\nStudent Menu:\n");
printf("1. Submit an assignment\n");
printf("2. See the submitted assignment\n");
printf("3. See the graded assignment\n");
printf("4. Exit\n");
printf("Please enter a number from 1 - 4: ");
scanf("%d", &choice);
switch (choice) {
case 1:
submitAssignment(assignmentStruct, "myassignment.txt");
break;
case 2:
getAssignment(assignmentStruct);
displayAssignment(assignmentStruct);
break;
case 3:
getGradedAssignment(assignmentStruct);
displayGradedAssignment(assignmentStruct);
break;
case 4:
exit(0);
break;
}
} while (choice != 5);
}
void readRemainingLines(FILE* pFile, char* assignment){
long charsRead = 0;
while(fgets(assignment + charsRead, MAX_ASSIGNMENT_SIZE - charsRead, pFile)!= NULL)
{
charsRead = strlen(assignment);
if(charsRead >= MAX_ASSIGNMENT_SIZE - 1) //Credits: Carl Gelfand
break;
}
assignment[MAX_ASSIGNMENT_SIZE-1] = 0; //Just to make sure.
}
//Reads the file whose name is provided as string “fileName”,
//and creates a file named “submission.txt” as specified in the functional specification.
//It returns a 1 when it is successful, otherwise it returns a 0.
int submitAssignment(Assignment* assignmentStruct, char* fileName) {
FILE* pFile =0;
//char assignment[MAX_ASSIGNMENT_SIZE];
char* submissionFileName="submission.txt";
//Reading information from a user provided file : fileName
pFile = fopen(fileName,"r");
if(pFile==NULL){
printf("%s file did not open\n,",fileName);
exit(0);
}//EO if(pFile==NULL)
printf("Please enter the name of the assignment: ");
scanf(" %s", assignmentStruct->assignmentName);
printf("Please enter your (student) name: ");
scanf(" %s", assignmentStruct->studentName);
readRemainingLines(pFile, assignmentStruct->assignment);
fclose(pFile);
// Writing Information to "submission.txt"
pFile = fopen(submissionFileName, "w");
if(pFile == NULL) {
printf("%s file did not open\n,", submissionFileName);
exit(0);
} //EO if(pFile==NULL)
fprintf(pFile, "%s\n", assignmentStruct->assignmentName);
fprintf(pFile, "%s\n", assignmentStruct->studentName);
fprintf(pFile, "%s\n", assignmentStruct->assignment);
fclose(pFile);
return 1;
}
int getAssignment(Assignment* assignmentStruct) {
FILE* pFile = 0;
pFile = fopen("submission.txt","r");
if(pFile==NULL){
printf("file did not open\n,");
exit(0);
}
fscanf(pFile, "%[^\n]", assignmentStruct->assignmentName);
fscanf(pFile, "%[^\n]", assignmentStruct->studentName);
readRemainingLines(pFile, assignmentStruct->assignment);
return 1;
}
void displayAssignment(Assignment* assignmentStruct) {
char* middleOfAssignment = &(assignmentStruct->assignment[strlen(assignmentStruct->assignmentName) + strlen(assignmentStruct->studentName) + 2]);
print(assignmentStruct->assignmentName, assignmentStruct->studentName);
printf("%s \n", middleOfAssignment);
//printf("%s \n", assignment);
}
void print(char* assignmentName, char* studentName) {
printf("Assignment Name: %s \nStudent: %s\n", assignmentName, studentName);
}
displayAssignment is skipping over the first few characters of the assignment when it assigns middleOfAssignment. It's skipping the first strlen(assignmentStruct->assignmentName) + strlen(assignmentStruct->studentName) + 2 characters.
It should just print assignmentStruct->assignment, there's no need for middleOfAssignment. The only reason for that code would be if assignment contained a copy of the assignment name and student name at the beginning, but it doesn't.
void displayAssignment(Assignment* assignmentStruct) {
print(assignmentStruct->assignmentName, assignmentStruct->studentName);
printf("%s \n", assignmentStruct->assignment);
}

Resources