Read a file through a function + Structure - c

I have a structure, a txt file that I want to read and the following code that works fine.
I am trying to make a function to include most of the read file functions there but seem to have problems with local variables etc..
#include <stdio.h>
#include <string.h>
int i,j,numberofseats,temp;
char platenr[8],selection,buff[60];
char firstname[20];
char lastname[20];
char phone[11];
char *p;
typedef struct
{
char fullname[40];
unsigned short phonenr[10];
unsigned int seatnr;
}PASSENGERS;
int main(void)
{
FILE *businfo;
businfo = fopen ("bus.txt","r");
if (businfo == NULL)
{
printf("Error Opening File, check if file bus.txt is present");
exit(1);
}
fscanf(businfo,"%s %d",platenr, &numberofseats);
printf("Bus Licence plate Nr is: %s and number of seats is: %d", platenr, numberofseats);
PASSENGERS passenger[numberofseats];
for (j=0;j<numberofseats;j++)
{passenger[j].seatnr=j+1;
strcpy(passenger[j].fullname,"\0");
}
while (fgets(buff,sizeof(buff),businfo))
{sscanf(buff, "%s %s %d %s", firstname, lastname, &temp,phone);
strcpy(passenger[temp-1].fullname,firstname);
strcat (passenger[temp-1].fullname, " ");
strcat(passenger[temp-1].fullname,lastname);
i=0;
for (p=phone;*p!='\0';p++)
{
(passenger[temp-1].phonenr[i])=*p -'0';
i++;
}
}
So after the code that works, this is the function I created,
where target should be defined, to update the structure
but the *target is not known yet since it is inside the txt file (the temp variable) that is going to be read by the function..
This is driving me nuts!
void readfile( PASSENGERS *target, FILE *businfo){
while (fgets(buff,sizeof(buff),businfo))
{sscanf(buff, "%s %s %d %s", firstname, lastname, &temp,phone);
strcpy(target->fullname,firstname);
strcat (target->fullname, " ");
strcat(target->fullname,lastname);
i=0;
for (p=phone;*p!='\0';p++)
{
(target->phonenr[i])=*p -'0';
i++;
}
}}

Look at the difference between the readfile function you created and the pure code in main function. The problem is you fill correctly the array passengers by indexing each element (passenger[temp-1]) in your main function but the readfile function fills only the first element of the array each time the while loop is executed.
There are two solutions:
1st solution: the pointer target points to the same element (first one) once the function is executed (fill each element using (target+temp-1)-> )
void readfile( PASSENGERS *target, FILE *businfo)
{
while (fgets(buff,sizeof(buff),businfo))
{
sscanf(buff, "%s %s %d %s", firstname, lastname, &temp,phone);
strcpy((target+temp-1)->fullname,firstname);
strcat ((target+temp-1)->fullname, " ");
strcat((target+temp-1)->fullname,lastname);
i=0;
for (p=phone;*p!='\0';p++)
{
((target+temp-1)->phonenr[i])=*p -'0';
i++;
}
}
}
2nd solution: the pointer target points to the last non-null element in the array once the function is executed (increment the pointer at the end of while loop)
void readfile( PASSENGERS *target, FILE *businfo)
{
while (fgets(buff,sizeof(buff),businfo))
{
sscanf(buff, "%s %s %d %s", firstname, lastname, &temp,phone);
strcpy(target->fullname,firstname);
strcat (target->fullname, " ");
strcat(target->fullname,lastname);
i=0;
for (p=phone;*p!='\0';p++)
{
(target->phonenr[i])=*p -'0';
i++;
}
target = target + temp - 1;
}
}

thanks for the advice everyone! I have the variables set as global because I will need them further down my program..
What I have done is transfer most of the file read code to the function that I set to have no iputs and outputs..
I also do the initialization of the structure by placing \0 into passenger names, and a seat nr from 1 to numberofseats..
I want for each line of the txt file the program to read the temp, and then in the structure PASSENGERS change the values passenger[temp]
The problem is that at this time everything gets ruined and when run it chaos appears with strange values.. I have included the whole code in case you want to run it, but the problem is only in the beginning..
#include <stdio.h>
#include <string.h>
int i,j,numberofseats,temp;
char platenr[8],selection,buff[60];
char firstname[20];
char lastname[20];
char phone[11];
char *p;
typedef struct
{
char fullname[40];
unsigned short phonenr[10];
unsigned int seatnr;
}PASSENGERS;
void readfile( void)
{
FILE *businfo;
businfo = fopen ("bus.txt","r");
if (businfo == NULL)
{
printf("Error Opening File, check if file bus.txt is present");
exit(1);}
else
{
fscanf(businfo,"%s %d",platenr, &numberofseats);
printf("Bus Licence plate Nr is: %s and number of seats is: %d", platenr, numberofseats);
PASSENGERS passenger[numberofseats];
for (j=0;j<numberofseats;j++)
{passenger[j].seatnr=j+1;
strcpy(passenger[j].fullname,"\0");
}
while (fgets(buff,sizeof(buff),businfo))
{sscanf(buff, "%s %s %d %s", firstname, lastname, &temp,phone);
strcpy(passenger[temp-1].fullname,firstname);
strcat (passenger[temp-1].fullname, " ");
strcat(passenger[temp-1].fullname,lastname);
i=0;
for (p=phone;*p!='\0';p++)
{
(passenger[temp-1].phonenr[i])=*p -'0';
i++;
}
}
}
}
int main(void)
{
readfile();
PASSENGERS passenger[numberofseats];
do{
printf("\n\nNeo Sistima katagrafis thesewn leoforeiou\n");
printf("Please make a selection:\n\n");
printf("0. Exit\n");
printf("1. Empty Seats \n");
printf("2. Book Specific Seat \n");
printf("3. Advanced Search of booked Seats\n");
printf("4. Cancel Seat Booking\n");
printf("5. Show List of booked Seats\n");
scanf(" %c",&selection);
if (selection=='1')
{int freeseats = 0;
for (j=0; j<numberofseats; j++)
{
strcmp(passenger[j].fullname,"\0")==0 ? freeseats = freeseats + 1 : freeseats ;}
printf ("There are %d free seats in this bus \n", freeseats);
printf("Seats that are available are:\n");
for (j=0; j<numberofseats; j++)
{if (strcmp(passenger[j].fullname,"\0")==0)
printf ("%u\n", passenger[j].seatnr);
}
freeseats = 0;
}
else if (selection=='2')
{
printf("Please give seat nr (between 1 and %d) that you want to book:\n", numberofseats);
scanf("%d",&temp);
if (temp >numberofseats || temp <= 0)
{printf("Error: Seat nr should be between 1 and %d", numberofseats);}
else if (strcmp(passenger[temp-1].fullname,"\0")!=0)
printf("Error: Seat is already booked");
else
changeData(&passenger[temp-1]);
}
else if (selection=='3')
{
char tempsel,tmpfirst[20],tmplast[20];
unsigned short tempphone[10];
int counter, checkphone;
unsigned int tempseat;
printf("Do you want to search with Name (1) or Phone Nr (2)?\n");
scanf(" %c",&tempsel);
if (tempsel == '1')
{ printf("Enter passenger first name:");
scanf("%s",tmpfirst);
printf("Enter passenger last name:");
scanf("%s",tmplast);
strcat (tmpfirst, " ");
strcat(tmpfirst,tmplast);
for (j=0;j<numberofseats;j++)
if (strcmp(passenger[j].fullname,tmpfirst)==0)
printf ("passenger %s has seat nr #: %u\n",tmpfirst,passenger[j].seatnr);
}
else if (tempsel == '2')
{ checkphone=0;
printf("Enter passenger phonenr:");
for (i=0;i<10;i++)
scanf("%hu",&tempphone[i]);
for (j=0;j<numberofseats;j++)
{
counter=0;
for(i=0;i<10;i++)
{
if (passenger[j].phonenr[i]==tempphone[i])
counter=counter+1;
if (counter ==10)
{checkphone=1;
tempseat=passenger[j].seatnr;
}}
}
if (checkphone==1)
{printf ("passenger has seat #: %u\n",tempseat);
checkphone=0;}
}
}
else if (selection=='4')
{
printf("Please give seat nr (between 1 and %d) that you want to cancel booking:\n", numberofseats);
scanf("%d",&temp);
if (temp >numberofseats || temp <= 0)
{printf("Error: Seat nr should be between 1 and %d", numberofseats);}
else if (strcmp(passenger[temp-1].fullname,"\0")==0)
printf("Error: Seat is already free");
else
cancelSeat(&passenger[temp-1]);
}
else if (selection=='5') /*Menu 6 - Emfanisi listas kratimenon thesewn taksinomimenon kata ayksonta arithmo*/
{
printf("The following seats are booked: \n Name, PhoneNr, SeatNr\n\n"); /*Emfanisi minimatos*/
for (i=0; i<numberofseats; i++)
if (strcmp(passenger[i].fullname,"\0")!=0)
{
printf("%s, ",passenger[i].fullname);
for (j=0;j<10;j++)
{printf("%hu",passenger[i].phonenr[j]);}
printf(", %u\n",passenger[i].seatnr);
}
}
} while (selection!='0');
}

(You should have added the second version of your program to the question rather than posting it as an answer.)
What I have done is transfer most of the file read code to the function that I set to have no iputs and outputs..
The problem is that at this time everything gets ruined and when run it chaos appears with strange values..
That is because in the function readfile() the data is read into a local array passenger, which is deallocated upon block exit, and thereafter the program uses a homonymous, yet other array, which is uninitialized. To rectify that, allocate the array in readfile() so that (the address of) it can be returned from the function, and use the returned memory. Required changes:
void readfile( void)
{
…
PASSENGERS passenger[numberofseats];
…
{sscanf(buff, "%s %s %d %s", firstname, lastname, &temp,phone);
…
}
}
}
…
readfile();
PASSENGERS passenger[numberofseats];
to
PASSENGERS *readfile(void)
{
PASSENGERS *passenger;
…
passenger = malloc(numberofseats * sizeof *passenger);
if (!passenger) exit(!!numberofseats); // 0: no seats, 1: no memory
…
{ if (sscanf(buff, "%s %s %d %s",
firstname, lastname, &temp, phone) < 4) continue;
…
}
}
return passenger;
}
…
PASSENGERS *passenger = readfile();
Note that we have to check the return value of sscanf() - this is vital, since after the fscanf(businfo,"%s %d",platenr, &numberofseats), the first \n remains in the input stream buffer, so the first fgets reads an empty line.
Note also that you still have to work on the phone number storage, as Weather Vane wrote.

Related

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

How can I utilize struct arrays to output a given struct based on user-input

ISSUE: I'm trying to fill my beerData struct with data found in beer.dat, except I don't understand how structs work well enough to implement without crashing my code. I believe I need an array of structs.
The beer.dat file contents:
7 // total number of beers
Coors //beer name
1234567 // beer id
72 // beer quantity
7.40 //beer price
Miller
7777777
44
9.70
Bud
7654321
345
9.90
Wachusett
7799435
4
14.70
Corona
9999999
112
9.99
Zima
0000000
1
0.01
Mikes
0890398
12
10.99
CODE:
/*
User interface, alloc, malloc 13 points
Correct structure and array built 7 points
Recursive sort
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct beerData {
char *beer[7]; // number of brands
char *beer_name; //names
int beer_id[7]; //ID number given to beer
int beer_quantity; //stock
float beer_price; // pricing
} beer_data;
void printStr(char *line) {
char *look = "";
printf("What would you like to search for? \n");
scanf("%s", look);
//printf("Line: %s\n", line);
exit(0);
}
void search() {
//look through beer.dat for a specific beer by ID number.
char str[32];
FILE *fp = fopen("beer.dat", "r");
if (fp == NULL) {
printf("Error: can't open file to read\n");
} else {
while (!feof(fp)) {
fscanf(fp, "%s ", str);
//printf("%s\n",str);
printStr(str);
}
}
fclose(fp);
}
int main() {
int user_choice;
printf("Enter 1 to search for a beer, 2 to view the entire catalogue,"
" and 3 to place an order, press 4 to exit.\n");
while (user_choice != 4) {
scanf("%d", &user_choice);
switch (user_choice) {
case 1:
printf("Searching for a beer\n");
user_choice = 0;
search();
break;
case 2:
printf("Viewing Inventory\n");
//viewInv();
break;
case 3:
printf("Placing an order...\n");
//placeOrder();
break;
case 4:
printf("Goodbye!\n");
exit(0);
default:
printf("Incorrect entry, try again.\n");
continue;
}
}
}
I'm trying create a function that searches through the file, and finds a specific beer based on an ID given, that ID is inside a set that should be its struct... so once the ID is input, the program searches for the beer, and prints out the name, ID, quantity, and price.
For full clarity, I'll post the assignment questions in case I'm not conveying my needs properly. The assignment is to:
Searching for a beer should prompt the user for an ID number and the result should display its quantity and price, if it is in your inventory.
A view of the entire inventory will display all the beers with their ID number, price and quantity in ascending order by price. This sorting should be done using either Recursive Bubble or Recursive Selection sort.
When placing an order an invoice of the order should be printed to the screen.
First you need to declare a meaningful structure. The structure contains relevant information for each item. Example:
typedef struct beer_data
{
char name[20]; //names
int id; //ID number given to beer
int quantity; //stock
float price; // pricing
} beer_data;
Next, you need an array of this structure. Use malloc to allocate enough memory for total number of items. Example:
beer_data *beers = malloc(total * sizeof(beer_data));
Now you have beers[0], beers[1], beers[2]..., read each item in the file and put that in the structure.
To read the file, you can use fscanf or fgets.
The first line in your file is
7 // total number of beers
You can read the number 7 using fscanf:
int maximum = 0;
fscanf(fp, "%d", &maximum);
This should work fine, but there are characters after that which you are not interested in. Use fgets to read to the end of the line and discard those characters.
Start a loop and read each line, add to the structure.
With this method, if you are adding a new item, then you have to increase the memory size. See add_item which uses realloc. This might be too advanced. Alternatively, you can save the new item to the file, call free(beers), and read the file again.
typedef struct beer_data
{
char name[20]; //names
int id; //ID number given to beer
int quantity; //stock
float price; // pricing
} beer_data;
void search_by_name(beer_data *beers, int total)
{
char buf[20];
printf("Enter name to search: ");
scanf("%19s", buf);
//note, we put %19s because beers[count].name is only 20 bytes long
for(int i = 0; i < total; i++)
{
if(strcmp(beers[i].name, buf) == 0)
{
printf("Found: %s, %d, %d, %.2f\n",
beers[i].name, beers[i].id, beers[i].quantity, beers[i].price);
return;
}
}
printf("%s not found\n", buf);
}
void print_list(beer_data *beers, int total)
{
for(int i = 0; i < total; i++)
{
printf("%s %d %d %.2f\n",
beers[i].name, beers[i].id, beers[i].quantity, beers[i].price);
}
}
void add_item(beer_data *beers, int *total)
{
//note, total has to be passed as pointer
//because we are changing it
//allocate more memory:
beers = realloc(beers, sizeof(beer_data) * (*total + 1));
printf("enter name: ");
scanf("%19s", beers[*total].name);
printf("enter id:");
scanf("%d", &beers[*total].id);
printf("enter quantity:");
scanf("%d", &beers[*total].quantity);
printf("enter price:");
scanf("%f", &beers[*total].price);
//increase the total
*total += 1;
}
int main()
{
FILE *fp = fopen("beer.dat", "r");
if(!fp)
{
printf("Error: can't open file to read\n");
return 0;
}
char buf[500];
int maximum = 0;
fscanf(fp, "%d", &maximum);
//read the rest of the line and discard it
fgets(buf, sizeof(buf), fp);
//allocate memory
beer_data *beers = malloc(maximum * sizeof(beer_data));
int total = 0;
while(1)
{
fgets(buf, sizeof(buf), fp);
sscanf(buf, "%19s", beers[total].name);
if(fscanf(fp, "%d", &beers[total].id) != 1) break;
fgets(buf, sizeof(buf), fp);
if(fscanf(fp, "%d", &beers[total].quantity) != 1) break;
fgets(buf, sizeof(buf), fp);
if(fscanf(fp, "%f", &beers[total].price) != 1) break;
fgets(buf, sizeof(buf), fp);
total++;
if(total == maximum)
break;
}
fclose(fp);
int stop = 0;
while (!stop)
{
printf("\
Enter 0 to exit\n\
Enter 1 print list\n\
Enter 2 for search\n\
Enter 3 add new item\n");
int choice;
scanf("%d", &choice);
switch(choice)
{
case 0:
stop = 1;
break;
case 1:
print_list(beers, total);
break;
case 2:
search_by_name(beers, total);
break;
case 3:
add_item(beers, &total);
break;
}
printf("\n");
}
//cleanup:
free(beers);
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);
}

New to C, need assistance with function related to structures

I need to make the second function (search_pb) print all matching names entered in the personal_info struct. Right now if there are two duplicate first names it only prints the first one. For example, if I added
First name: "Albert"
Last name: "Einstein"
Phone number:35245
and also added
First name: "Albert"
Last name: "Wesker"
Phone number:17367
it would only print the first Albert entered instead of both when I search for "Albert". Any ideas on how to change this?
#include <stdio.h>
#include <string.h>
#include "libpb.h"
void add_person(struct phone_book * pb, struct personal_info person)
{
int num = pb->num_people;
strcpy(pb->person[num].first, person.first);
strcpy(pb->person[num].last, person.last);
strcpy(pb->person[num].phone, person.phone);
num++;
pb->num_people = num;
}
void search_pb(struct phone_book pb, char find_name[])
{
int p;
for (p = 0; p < pb.num_people; p++)
{
if (strcmp(find_name, pb.person[p].first) == 0)
{
printf("\nName: %s %s\n", pb.person[p].first,
pb.person[p].last);
printf("Phone: %s\n", pb.person[p].phone);
return;
}
}
printf("No entries with that name. \n");
}
I was given the main function phone_book.c to work with so I just had to make the functions above and a header file:
#include <stdio.h>
#include <string.h>
#include "libpb.h"
int main ()
{
char cont;
char find_name[25];
struct phone_book pb;
pb.num_people = 0;
struct personal_info person;
printf("\n*********************************************\n");
printf("\n Start with entering new contacts! \n");
printf("\n*********************************************\n");
printf("\nWould you like to enter a new contact (Y/N): ");
while(pb.num_people < 20)
{
scanf("%c", &cont);
if (cont == 'Y')
{
printf("Enter a first name: ");
scanf("%s", person.first);
printf("Enter %s's last name: ", person.first);
scanf("%s", person.last);
printf("Enter %s's phone number: ", person.first);
scanf("%s", person.phone);
add_person(&pb, person);
}
else if (cont == 'N') break;
else if (cont == '\n') continue;
else printf("Error: User entered '%c'. Must enter either 'Y' or 'N'\n",
cont);
printf("\nWould you like to enter a new name (Y/N): ");
}
//search phone book by first name and print persons
printf("\n*********************************************\n");
printf("\n Now You can search for names! \n");
printf("\n*********************************************\n");
printf("\nWould you like to search for a name (Y/N)? ");
while(1)
{
scanf("%c", &cont);
if (cont == 'Y')
{
printf("Enter a person's name to search for: ");
scanf("%s", find_name);
//scanf("%c", &tmp);
search_pb(pb, find_name);
}
else if (cont == 'N') break;
else if (cont == '\n') continue;
else printf("Error: User entered '%c'. Must enter either 'Y' or 'N'\n",
cont);
printf("\nWould you like to search for a name (Y/N)? ");
}
return 0;
}
I also already made the necessary header file libpb.h:
#include<stdio.h>
#include<string.h>
#define MAX 20
#define _CRT_SECURE_NO_DEPRECATE
struct personal_info
{
char first[25];
char last[25];
char phone[15];
};
struct phone_book
{
struct personal_info person[MAX];
int num_people;
};
void add_person(struct phone_book *pb, struct personal_info person);
void search_pb(struct phone_book pb, char find_name[]);
A quick-and-dirty circumvention for this would be:
void search_pb(struct phone_book pb, char find_name[])
{
int matches = 0;
int p;
for (p = 0; p < pb.num_people; p++)
{
if (strcmp(find_name, pb.person[p].first) == 0)
{
printf("\nName: %s %s\n", pb.person[p].first,
pb.person[p].last);
printf("Phone: %s\n", pb.person[p].phone);
matches++;
}
}
if(matches == 0)
{
printf("No entries with that name. \n");
}
}
You could however, e.g. change search_pb() type to int, and return the match count after looping through, so that you can print "no matches" in the caller instead of printing them inside the function.

Buffer overflow or something else

I am creating a program, about seat reservations. I was asked to use unsigned short and unsigned int for some of the variables, so that is why they are set like that.
I have a program that works ok. But when I transfer everything inside a function, everything seems to work ok, but inside my structure weird values start to be saved all over the place..
I only want to save the values of the file (from line 2 -> the end of file).
Because I have a structure that to be initialized I have first to read the txt file and numberofseats, I have am declaring this variable (passenger) 2 times..inside the function (local var) and in the main body..
Maybe this causes the problem?
If I don't use a function everything work fine!
So the problematic code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int i,j,numberofseats,temp;
char platenr[8],selection,buff[60];
char firstname[20];
char lastname[20];
char phone[11];
char *p;
typedef struct
{
char fullname[40];
unsigned short phonenr[10];
unsigned int seatnr;
}PASSENGERS;
void readfile( void)
{
FILE *businfo;
businfo = fopen ("bus.txt","r");
if (businfo == NULL)
{
printf("Error Opening File, check if file bus.txt is present");
exit(1);}
else
{
fscanf(businfo,"%s %d",platenr, &numberofseats);
printf("Bus Licence plate Nr is: %s and number of seats is: %d", platenr, numberofseats);
PASSENGERS passenger[numberofseats];
for (j=0;j<numberofseats;j++)
{passenger[j].seatnr=j+1;
strcpy(passenger[j].fullname,"\0");
}
while (fgets(buff,sizeof(buff),businfo)!=0)
{sscanf(buff, "%s %s %d %s", firstname, lastname, &temp,phone);
strcpy(passenger[temp-1].fullname,firstname);
strcat (passenger[temp-1].fullname, " ");
strcat(passenger[temp-1].fullname,lastname);
printf("%s",passenger[temp-1].fullname);
i=0;
for (p=phone;*p!='\0';p++)
{
(passenger[temp-1].phonenr[i])=*p -'0';
i++;
}
}
}
}
int main(void)
{
readfile();
PASSENGERS passenger[numberofseats];
A variable called x in function foo has nothing to do with a variable called y in function bar. In other words: passenger in main and passenger in readfile are different variables. Changing one will not impact the other.
What you want is probably more like this:
int main(void)
{
PASSENGERS passenger[numberofseats];
readfile(passenger);
^^^^^^^^^
Pass array as a pointer
....
}
and
void readfile(PASSENGERS* passenger)
{
....
// REMOVE THIS: PASSENGERS passenger[numberofseats];
}
Beside that notice:
// Global variables gets zero initialized
int i,j,numberofseats,temp;
^^^^^^^^^^^^
Becomes zero at start up
but still you use it in main:
PASSENGERS passenger[numberofseats];
That is probably no what you really want.
Since you try to read the number of seats in the function, it seams you really want to use dynamic memory allocation. Like:
PASSENGERS* readfile()
{
.....
.....
PASSENGERS* p = malloc(numberofseats * sizeof(PASSENGERS));
.....
.....
return p;
}
int main(void)
{
PASSENGERS* passenger = readfile();
.....
.....
free(passenger);
return 0;
}
If you don't want dynamic allocation, you must move the input of numberofseats into main so it is done before declaring the array.
The problem is that you are declaring a local array in the function readfile(), and once this function terminates, it is lost. You need to be able to return the changes to main(). For that you have some options. One is that you may declare the array in main(), and change your function to void readfile(PASSENGERS passenger[]). In this case, you will do something like this:
int main()
{
PASSENGERS passenger[numberofseats];
readfile(passenger);
// more code
You will be basically passing a pointer to the memory location of the elements stored in the array, local to main(), and the function will fill the array, effectively returning the changes.
Another option is to dynamically allocate an array (with malloc() family) in the function, and make it return a pointer like PASSENGERS *readfile(void). This option may be more suitable if the number of seats is not known at compile time, so you need to dynamically grow or shrink the array when necessary. This option however, leaves you the burden of managing the memory manually, like free()'ing the allocated memory when you are done.
Since you say that you will read numberofseats from the file, the latter would be the better idea, so your code will look something like this:
PASSENGERS *readfile(void)
{
FILE *businfo;
PASSENGERS *passenger;
businfo = fopen ("bus.txt","r");
// do the checks, read the numberofseats
passenger = malloc(numberofseats * sizeof *passenger);
// read the values, fill the array
fclose(businfo); // do not forget to close the file
return passenger;
}
int main()
{
PASSENGERS *passenger = readfile();
// more code
free(passenger);
return 0;
}
Ok, so what I did, before starting to work on dynamic allocation is specify the max number of seats in the start of main, and from there I finished my code as follows. I have 2 warning messages though in lines 43, 109 that can't seem to be able to fix.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int i,j,numberofseats,temp;
char platenr[8],selection;
char firstname[20],lastname[20];
char phone[11];
char *p;
typedef struct
{
char fullname[40];
unsigned short phonenr[10];
unsigned int seatnr;
}PASSENGERS;
void readfile(PASSENGERS passenger[])
{ char buff[60];
FILE *businfo;
businfo = fopen ("bus.txt","r");
if (businfo == NULL)
{
printf("Error Opening File, check if file bus.txt is present");
exit(1);}
else
{
fscanf(businfo,"%s %d",platenr, &numberofseats);
printf("Bus Licence plate Nr is: %s, and Number of Seats is: %d.", platenr, numberofseats);
for (j=0;j<numberofseats;j++)
{passenger[j].seatnr=j+1;
strcpy(passenger[j].fullname,"\0");
}
while (fgets(buff,sizeof(buff),businfo)!=0)
{sscanf(buff, "%s %s %d %s", firstname, lastname, &temp,phone);
strcpy(passenger[temp-1].fullname,firstname);
strcat (passenger[temp-1].fullname, " ");
strcat(passenger[temp-1].fullname,lastname);
i=0;
for (p=phone;*p!='\0';p++)
{
(passenger[temp-1].phonenr[i])=*p -'0';
i++;
}
}
}
}
void countfreeseats(PASSENGERS passenger[]){
int freeseats = 0;
for (j=0; j<numberofseats; j++)
{
strcmp(passenger[j].fullname,"\0")==0 ? freeseats = freeseats + 1 : freeseats ;}
printf ("There are %d Free Seats in this Bus. \n", freeseats);
printf("Seats that are Available are:\n");
for (j=0; j<numberofseats; j++)
{if (strcmp(passenger[j].fullname,"\0")==0)
printf ("%u\n", passenger[j].seatnr);
}
freeseats = 0;
}
void changeData(PASSENGERS *target){
unsigned short tempdigit;
printf("Enter Passenger's first name:");
scanf("%s",firstname);
printf("Enter Passenger's last name:");
scanf("%s",lastname);
strcpy(target->fullname,firstname);
strcat (target->fullname, " ");
strcat(target->fullname,lastname);
printf("Enter Passenger's phone Nr:");
scanf("%s",phone);
i=0;
for (p=phone;*p!='\0';p++)
{
(target->phonenr[i])=*p -'0';
i++;
}
}
void searchpassenger(PASSENGERS passenger[], char selection)
{ char tempsel,tmpfirst[20],tmplast[20];
unsigned short tempphone[10];
if (selection == '1')
{ printf("Enter Passenger's first name:");
scanf("%s",tmpfirst);
printf("Enter Passenger's last name:");
scanf("%s",tmplast);
strcat (tmpfirst, " ");
strcat(tmpfirst,tmplast);
for (j=0;j<numberofseats;j++)
if (strcmp(passenger[j].fullname,tmpfirst)==0)
printf ("Passenger %s has Seat Nr #: %u\n",tmpfirst,passenger[j].seatnr);
}
else if (selection == '2')
{ printf("Enter Passenger's Phone Nr:");
scanf("%s",phone);
i=0;
for (p=phone;*p!='\0';p++)
{
(tempphone[i])=*p -'0';
i++;
}
for (j=0;j<numberofseats;j++)
{if (strcmp(tempphone,passenger[j].phonenr)==0)
printf("Passenger %s has Seat Nr %hd already Booked",passenger[j].fullname,passenger[j].seatnr);
}
}
}
void cancelSeat(PASSENGERS *target){
strcpy(target->fullname,"\0");
for (i=0;i<10;i++)
target->phonenr[i]=0;
printf("Seat Nr %d is now Free",temp);
}
void showList(PASSENGERS passenger[])
{
printf("The following Seats are Booked: \n Name, PhoneNr, SeatNr\n\n"); /*Emfanisi minimatos*/
for (i=0; i<numberofseats; i++)
if (strcmp(passenger[i].fullname,"\0")!=0)
{
printf("%s, ",passenger[i].fullname);
for (j=0;j<10;j++)
{printf("%hu",passenger[i].phonenr[j]);}
printf(", %u\n",passenger[i].seatnr);
}
}
void writeFile(PASSENGERS passenger[])
{
FILE * output; /* Dilosi onomatos arxeiou */
output = fopen("output.txt","w"); /*dimiourgia i eggrafi pano se iparxon arxeio me onoma output.txt, mesw tis parametrou w*/
fprintf(output,"%s %d \n",platenr,numberofseats); /* mesw tis fprintf eksagogi pinakidas kai epikefalidas "Diagramma leoforeiou" sto arxeio output.txt. Allagi grammis opou xreiazetai*/
for (i=0; i<numberofseats; i++)
{if (strcmp(passenger[i].fullname,"\0")!=0)
{
fprintf(output,"%s ",passenger[i].fullname);
fprintf(output,"%u ",passenger[i].seatnr);
for (j=0;j<10;j++)
fprintf(output,"%hu",passenger[i].phonenr[j]);
fprintf(output,"%s","\n");
}
}
fclose(output); /* Kleisimo arxeiou*/
printf("File Saved as Output.txt");
}
int main(void)
{
PASSENGERS passenger[53];
readfile(passenger);
do{
printf("\n\nNeo Sistima Katagrafis Thesewn Leoforeiou\n");
printf("Please make a selection:\n\n");
printf("0. Exit\n");
printf("1. Empty Seats \n");
printf("2. Book Specific Seat \n");
printf("3. Advanced Search of Booked Seats\n");
printf("4. Cancel Seat Booking\n");
printf("5. Show List of Booked Seats\n");
scanf(" %c",&selection);
if (selection=='1')
countfreeseats(passenger);
else if (selection=='2')
{
printf("Please give seat nr (between 1 and %d) that you want to book:\n", numberofseats);
scanf("%d",&temp);
if (temp >numberofseats || temp <= 0)
{printf("Error: Seat nr should be between 1 and %d", numberofseats);}
else if (strcmp(passenger[temp-1].fullname,"\0")!=0)
printf("Error: Seat is already booked");
else
changeData(&passenger[temp-1]);
}
else if (selection=='3')
{
char tempsel;
printf("Do you want to search with Name (1) or Phone Nr (2)?\n");
scanf(" %c",&tempsel);
searchpassenger(passenger,tempsel);
}
else if (selection=='4')
{
printf("Please give Seat Nr (between 1 and %d) that you want to Cancel Booking:\n", numberofseats);
scanf("%d",&temp);
if (temp >numberofseats || temp <= 0)
{printf("Error: Seat nr should be between 1 and %d", numberofseats);}
else if (strcmp(passenger[temp-1].fullname,"\0")==0)
printf("Error: Seat is already free");
else
cancelSeat(&passenger[temp-1]);
}
else if (selection=='5') /*Menu 6 - Emfanisi listas kratimenon thesewn taksinomimenon kata ayksonta arithmo*/
{
showList(passenger);
}
} while (selection!='0');
{
writeFile(passenger);
}
}

Resources