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);
}
}
Related
Kindly help me debug this code. It is not displaying the correct data. The following program is supposed to get book details from the user, dynamically allocate memory to them and display them.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "problem5.h"
int main()
{
struct books *b;
b = (struct books*)malloc(sizeof(struct books));
int command, flag = 0;
int n=0, i;
while(flag == 0)
{
printf ("1. Add Book\n");
printf ("2. View Books\n");
printf ("3. Quit\n");
scanf("%d", &command);
if (command == 1)
{
printf ("Enter Name\n");
//scanf("%d", &(b+i)->name);
scanf(" ");
gets((b+i)->name);
printf ("Enter Author\n");
//scanf("%d", &(b+i)->author);
scanf(" ");
gets((b+i)->author);
printf ("Enter Year Published\n");
scanf("%d", &(b+i)->year_published);
n=n+1;
i=n;
} else if (command == 2)
{
for(i=0; i<n; i++)
{
printf ("%d - %d by %d\n", (b+i)->year_published, (b+i)->name, (b+i)->author);
}
} else if (command == 3)
{
flag = 1;
} else
{
printf ("Invalid choice!\n");
}
}
}
The following is problem5.h header file that has the structure books. Initially I didn't declare the variables in array since I didn't want to use much memory. But I had to due to many errors.
#define PROBLEM3_H_INCLUDED
typedef struct books{
char *name[30];
char *author[30];
int year_published;
};
#endif // PROBLEM3_H_INCLUDED
When I print I am getting random numbers instead of the data the user entered.
The overall design of your code is wrong.
This is basically what you want.
I made following changements:
using meaningful variable names
changed struct book so the structure can contain one book. Also renamed it from struct books to struct book because the structure contains only one book.
allocating memory properly
using books[numberofbooks].x instead of the less readable *(books + numberofbooks)->x
More explanations in the comments.
#include <stdio.h>
#include <stdlib.h>
struct book {
char name[30];
char author[30];
int year_published;
};
int main()
{
struct book* books = NULL; // no books at all initially so we
// initialize to NULL
// so we can simply use realloc
int numberofbooks = 0;
int programend = 0;
while (programend == 0)
{
printf("1. Add Book\n");
printf("2. View Books\n");
printf("3. Quit\n");
int command;
scanf("%d", &command);
if (command == 1)
{
getchar(); // consume Enter key (due su scanf)
// allocate memory for one more book
books = realloc(books, sizeof(struct book) * (numberofbooks + 1));
printf("Enter Name\n");
gets(books[numberofbooks].name);
printf("Enter Author\n");
gets(books[numberofbooks].author);
printf("Enter Year Published\n");
scanf("%d", &books[numberofbooks].year_published);
numberofbooks++; // increment number of books
}
else if (command == 2)
{
for (int i = 0; i < numberofbooks; i++)
{
printf("%d - %s by %s\n", books[i].year_published, books[i].name, books[i].author);
}
}
else if (command == 3)
{
programend = 1;
}
else
{
printf("Invalid choice!\n");
}
}
}
There is still room for improvement though:
error checking for realloc
error checking for interactive I/O
not using the deprecated and dangerous gets
and certainly a few other things
b = (struct books*)malloc(sizeof(struct books));
Here, you are allocating memory for only one instance of struct books , But you are accessing multiple instances of struct books.
printf ("%d - %d by %d\n", (b+i)->year_published, (b+i)->name, (b+i)->author);
For i>=1 (b+i) is not defined, because you did not allocate memory for it. You have allocated memory for only (b+0).
int n=0, i;
gets((b+i)->name);
Here, i has not been initiliazed.
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;
}
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.
I've been writing a small program that will allow the user to read a file, create a small "database" and the ability to create / delete entries, etc. When I try to use the
realloc()
function, it crashes.
Not sure if I am doing something wrong, probably am though, since I'm rather new to C.
So, I try to do it this way:
StudentDB database;
//More code in between, that does include malloc()
database->students = realloc(database->students, (database->numberOfStudents + 1) * sizeof(Student));
//It crashes when it gets to that part.
What I am trying to do is use the realloc() function for a pointer that's inside a struct.
This is the entire program so far:
#include <stdio.h>
#include <stdlib.h>
typedef struct Lesson {
char *name;
int semester;
float grade;
} Lesson;
typedef struct Student {
char *name;
char *surname;
int id;
int numberOfLessons;
Lesson *lesson;
} Student;
typedef struct Database {
int numberOfStudents;
Student *student;
} StudentDB;
static int maxNameSize = 100;
static int autoclear = 1;
void addStudent(FILE *studentFile, StudentDB *database) {
database->numberOfStudents++;
printf("\nAdded +1 to number of students");
database->student = realloc(&database->student, 10);
//
// printf("Name of the student: ");
// scanf("%s", database.student[database.numberOfStudents].name);
}
void clear() {
if(autoclear) {
system("cls");
}
}
Lesson getNextLesson(FILE *studentFile) {
Lesson lesson;
lesson.name = malloc(maxNameSize * sizeof(char));
if(!lesson.name) { printf("Memory Allocation has failed. Exiting the program!"); exit(0); }
fscanf(studentFile, "%s", lesson.name);
fscanf(studentFile, "%d", &lesson.semester);
fscanf(studentFile, "%f", &lesson.grade);
printf("\n\t%s %d || %.2f\n", lesson.name, lesson.semester, lesson.grade);
return lesson;
}
Student getNextStudent(FILE *studentFile) {
Student student;
student.name = malloc(maxNameSize * sizeof(char));
if(!student.name) { printf("Memory Allocation has failed. Exiting the program!"); exit(0); }
fscanf(studentFile, "%s", student.name);
student.surname = malloc(maxNameSize * sizeof(char));
if(!student.surname) { printf("Memory Allocation has failed. Exiting the program!"); exit(0); }
fscanf(studentFile, "%s", student.surname);
fscanf(studentFile, "%d", &student.id);
fscanf(studentFile, "%d", &student.numberOfLessons);
printf("%d || %s %s || %d\n", student.id, student.name, student.surname, student.numberOfLessons);
int lesson;
student.lesson = malloc(student.numberOfLessons * sizeof(Lesson));
for(lesson = 0; lesson < student.numberOfLessons; lesson++) {
student.lesson[lesson] = getNextLesson(studentFile);
}
return student;
}
void loadStudents() {
}
void run(FILE *studentFile, StudentDB *database) {
int answer;
do {
clear();
answer = menu();
switch(answer) {
case 1: {
break;
}
case 2: {
break;
}
case 3: {
addStudent(studentFile, &database);
break;
}
case 4: {
break;
}
}
} while(answer < 0 || answer > 9);
}
int menu() {
int answer;
printf("1. Load students records from file\n");
printf("2. Save students records to file\n");
printf("3. Add a student record\n");
printf("4. Delete a student record by student id\n");
printf("5. Display a student record by student id\n");
printf("6. Display a student record by student surname\n");
printf("7. Display all student records\n");
printf("8. Find the lesson average for all students\n");
printf("9. Exit\n");
printf("Enter the number of the thing you would like to do: ");
// scanf("%d", &answer);
return 3;
}
void programInfo() {
printf("\n\n====================================================\n\tProgram Info\n\n This program was created by KKosyfarinis\n\n KKosyfarinis#uth.gr\n====================================================\n\n");
}
void readData(FILE *studentFile, StudentDB *db) {
int i;
printf("Running the loop\n");
for(i = 0; i < db->numberOfStudents; i++) {
printf("=====================\n\n\tStudent #%d\n", i);
db->student[i] = getNextStudent(studentFile);
printf("\n\tCompleted\n\n=====================\n");
}
clear();
}
void saveStudents() {
}
void main() {
system("color 02");
system("#echo off");
FILE *studentFile;
StudentDB database;
studentFile = fopen("students.txt", "r+w");
int numberOfStudents;
//Set the number of students
fscanf(studentFile, "%d", &database.numberOfStudents);
//Prints the number of students
printf("Number of students: %d\n", database.numberOfStudents);
//Set the memory allocation
database.student = malloc(database.numberOfStudents * sizeof(Student));
if(!database.student) {
printf("The memory allocation has failed. Exiting the program!");
exit(0);
}
//Read the students
readData(studentFile, &database);
programInfo();
run(studentFile, &database);
}
Thanks in advance for any help!
You're two code blocks have differing lines. One of which (the larger one) is incorrect. You are passing in a dereference to the student pointer? That's not needed, just pass the pointer itself.
database->student = realloc(&database->student, 10);
Should be:
database->student = realloc(database->student, 10);
You are also not passing in a realistic size, but your first code sample was. Does the following line not work?
database->students = realloc(database->students, (database->numberOfStudents + 1) * sizeof(Student));
That was just copied from your question. I'm confused as to what you have/have not tried and which one gives you the error.
Also, in the future provide more of a minimal example that still produces the error. There's also a chance you would figure out the issue while stripping the code down.
What with this line ?
addStudent(studentFile, &database);
in run function ? Where pointer to local variable is taken and passed to addStudent function
void run(FILE *studentFile, StudentDB *database) {
...
case 3: {
addStudent(studentFile, &database); // <-- get pointer to local variable
i think this code cannot work even with Nick's changes without this modification
addStudent(studentFile, database);
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.