While performing operations will the bookid's get changed? - c

I have made a program which is a small library operated via software. When I add two books and then delete the first book the second book gets the same bookid as the first book because of count-- in the del() function. I cannot rely on printing the count as the bookid. Is there a better option?
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
static int count;
struct book
{
int bookid;
char name[30];
char author[30];
float price;
};
struct book b[40];
void add(void);
void del(void);
void sort(void);
void price(void);
void print(void);
void main(void)
{
char choice;
while(1)
{
clrscr();
printf("Enter a choice:\n 1.Add a book.\n 2.Delete a book.\n 3.Sort books by price.\n 4.To print all books details.\n 5.To print the names of the books whose price is less than 1000.\n 6.Exit\n");
choice=getche();//doing by getch() as getche makes the program rough as it is printed
switch(choice)
{
case'1':add();break;
case'2':del();break;
case'3':sort();break;
case'4':print();break;
case'5':price();break;
case'6':exit(0);
default:printf("Enter a valid choice.");break;
}
}/*switch ends*/
}
void add(void)
{
int i;
char ch[30];
clrscr();
for(i=count;i<40;i++)
{
printf("Enter books name:\n");
gets(b[i].name);
printf("Enter author's name\n");
gets(b[i].author);
printf("Enter price:\n");
gets(ch);
b[i].price=atoi(ch);
printf("Dear User,the book has succesfully been added.The book id is %d",i);
count++;
break;
} /* for ends*/
getch();
}
void print(void)
{
int i;
clrscr();
for(i=0;i<count;i++)
{
printf("Bookid=%d,Name=%s,Author=%s,Price=%f\n",b[i].bookid,b[i].name,b[i].author,b[i].price);
}
getch();
}
void del(void)
{
int i,j;
char ch[10];
clrscr();
printf("Enter book id:");
gets(ch); // how do i put it into the structure as i dont know that which structure it belongs to
for(i=0;i<count;i++) //searching
{
if(b[i].bookid==atoi(ch))
{
for(j=i;j<count;j++)
{
b[j]=b[j+1];
}//for j ends
} //if ends
} /* for of i ends */
count--;
getch();
}
//void del(void)
//{
// int i;
// char ch[10];
// clrscr();
//printf("Enter book id:");
// gets(ch);
// for(i=0;i<40;i++)
// {
// b[i]=b[i+1];
//
// }
// count--;
// printf("Dear user,delete succesful");
//getch();
//}
void sort(void)
{
int i;
float temp;
for(i=0;i<40;i++)
{
if(b[i].price>b[i+1].price)
{
temp=b[i].price;
b[i].price=b[i+1].price;
b[i+1].price=temp;
}
}/*for ends*/
printf("Dear user,the books are sorted by price.\n");
getch();
}
void price(void)
{
int i;
clrscr();
for(i=0;i<count;i++)
{
if(b[i].price<1000)
{
printf("%d.%s\n",i+1,b[i].name);
}
}
getch();
}

One way is to have two global counters: one has the number of books stored, the other gives the next (unique) book id, as Tyler McHenry points out. When you delete a book, decrement the number of books, but never decrement the next book id.
I notice that when a book is deleted, you move the rest of the book entries together ("compress" them) so your array is always "dense". So another solution is to add a "deleted" flag to the book structure. Now you don't compress the entries when a book is deleted, but when a book is added, the code must search for an empty place in the array. Also the bookid is just the position in the array. (By the way, if you hard-code sizes, like the size of an array, do it once.)
#define MAXSTR (30)
struct book
{
int bookid;
int valid; // 1 is valid, 0 is empty or deleted
char name[MAXSTR];
char author[MAXSTR];
float price;
};
#define MAXBOOKS (40)
struct book b[MAXBOOKS];
int findEmpty()
{
int i;
for (i=0; i < MAXBOOKS; i++) {
if (! b[i].valid) return i;
}
return -1; // no more space
}
void add(void)
{
int i = findEmpty();
char ch[MAXSTR];
if (i < 0) return; // no room for more books
clrscr();
printf("Enter books name:\n");
fgets(b[i].name, MAXSTR, stdin);
printf("Enter author's name\n");
fgets(b[i].author, MAXSTR, stdin);
printf("Enter price:\n");
fgets(ch, MAXSTR, stdin);
b[i].price=atoi(ch);
/* Assign the empty location found to this book */
b[i].bookid = i;
/* mark that it is valid */
b[i].valid = 1;
printf("Dear User,the book has succesfully been added.The book id is %d", b[i].bookid);
getch();
}
del() now just marks the book as invalid. The main part of del() looks like this.
gets(ch);
int idToDelete = atoi(ch);
// find which structure it belongs to
for(i=0;i
Use a selection sort in sort() instead of the one-pass routine (which doesn't work in all cases) which is there. Printing books should skip any book that is not valid, too.

some pointers:
use fgets instead of gets, its safer
because you can specify max buf len
in add() there is no book id assigned,
so it will - due to being global -
remain 0
why do u need book id? you
have an array of 40, use the array
index as id.

Your first problem seems to be that you are never actually setting the bookid field of the book structure to anything. It will end up having some arbitrary value in each book struct, which will make it pure luck if del ever works correctly.
Your problem is in here:
printf("Enter books name:\n");
gets(b[i].name);
printf("Enter author's name\n");
gets(b[i].author);
printf("Enter price:\n");
gets(ch);
b[i].price=atoi(ch);
printf("Dear User,the book has succesfully been added.The book id is %d",i);
count++;
Take a look at this code, and show me where you set the value of b[i].bookid. The answer is nowhere. So try changing the last few lines to:
b[i].bookid = i;
printf("Dear User,the book has succesfully been added.The book id is %d", b[i].bookid);
count++;
Now, this still has a problem if you ever call add after calling del, because in the single-iteration loop that that code is in, i is always set to count. So, as you noticed, if count ever changes, which it will frequently, you will assign duplicate IDs. One solution is to define, at the top of the add function, a static variable (which retains its value between calls to the function) indicating what the next book id should be, like so:
void add(void)
{
static int nextBookId = 0;
int i = count;
char ch[30];
/* Do not overrun the array */
if (count >= 40) return;
clrscr();
printf("Enter books name:\n");
gets(b[i].name);
printf("Enter author's name\n");
gets(b[i].author);
printf("Enter price:\n");
gets(ch);
b[i].price=atoi(ch);
/* Assign the next unique book ID to this book, then increment nextBookId,
which will retain its incremented value next time you call add() */
b[i].bookid = nextBookId++;
printf("Dear User,the book has succesfully been added.The book id is %d", b[i].bookid);
count++;
getch();
}
Note that I replaced your loop with a simple bounds check at the top.
This way, every book you add gets its own, unique identifier that does not necessarily correspond to its position in the array or the number of books that existed at the time it was added. This method will not re-use IDs of previously deleted books, but that is probably a desirable behavior.

Related

How do I pass a airplane row and seat to a txt file together with its passenger name etc.?

We need to make a program for airplane seat reservation. Like we need a program which can reserve, change, delete, and display seats. But our program needs also to be written in a txt file as the user inputs data (name, age, city, seat-e.g., 1F). And I have made a program myself. It runs but exits halfway. And I am not sure if what I'm doing is right. I kind of get the gist on how I can pass informations using structs. But I don't know how I will the seats also in the txt file.
I have these on my first lines:
#include<stdio.h>
#include<malloc.h>
struct Passenger{
int pnum;
int age;
char city[50];
char name[50];
};
struct Seats{
int row;
char seats[10];
};
struct Airplane{
struct Seats seats[6];
};
void intializeDefault(struct Airplane *airplane){
for(int i=0;i<10;i++){
char ch='A';
airplane->seats[i].row=i+1;
for(int j=0;j<6;j++){
airplane->seats[i].seats[j]=ch;
ch++;
}
}
}
And well we kind of have commands, so I put it like:
int main(){
int ch;
struct Airplane airplane;
intializeDefault(&airplane);
do{
printf("Welcome to our Airlines!\n");
printf("\nOptions:");
printf("\n[1] Book a seat.");
printf("\n[2] Display seats.");
printf("\n[3] Change seat.");
printf("\n[4] Delete reservation.");
printf("\n[5] Display reservation records.");
printf("\n[0] Exit.");
printf("\nWhat can we do for you? (Enter number.): ");
scanf("%d", &ch);
switch(ch){
case 1:book();
break;
case 2:display(&airplane);
break;
case 3:change();
break;
case 4:deleteSeat();
break;
case 5:record();
break;
default:
break;
}
}while (ch!=0);
{
printf("\nThank you for booking !");
};
return 0;
}
What I need help on is how should I do on this part:
void book(){
struct Passenger *p;
FILE *fp;
struct Airplane airplane;
intializeDefault(&airplane);
int totalSeats = 60;
int seatsBooked = 0;
int n, i, j, row;
char seat;
printf("How many passengers/seats you want to reserve?: ");
scanf("%d", &n);
p = (struct Passenger*) malloc(n * sizeof(struct Passenger));
fp=fopen("Passengers.txt", "w");
if(seatsBooked==60){
printf("\nAll seats are booked now.");
}
for(i=0;i<n;i++){
printf("Enter Roll Number: ");
scanf("%d", p[i].pnum);
fflush(stdin);
printf("Enter #%d passenger's name: ", i+1);
scanf("%[^\n]s", p[i].name);
fflush(stdin);
printf("What's the passenger's age?: ");
scanf("%d", p[i].age);
fflush(stdin);
printf("Please enter the city where the passenger resides: ");
scanf("%d",p[i].city);
fflush(stdin);
printf("\nEnter Seat row: (Type 1-10) ");
scanf("%d", &row);
fflush(stdin);
printf("Enter Seat column: (Type A-F) ");
scanf("%c", &seat);
if(airplane.seats[row-1].seats[seat-'A']!='X'){
airplane.seats[row-1].seats[seat-'A']='X';
seatsBooked++;
printf("\nSeat %d%c is booked. \n\n", row, seat);
}
else{
printf("\nSeat %d%c is already booked.\n", row, seat);
}
}
fclose(fp);
}
I just need to know on how I can also pass every passenger's seats within on them, and I think I will figure out the other parts. It's because we need to show the records of passengers and their seat reservations when we command "5", and I need to show "X" on every reserved seats when we command "2". And I am not quite sure how I will do that. Should I change the functions on above? The structs? Or some lines?
I gave a quick look and I think that you should keep track of the booked seat by the single user... In your "Seats" struct, why don't you add an array of "Passenger" pointers in order to link every seat to the respective user?
As soon a user books a seat, you should have the index of the booked seat in a specific row. You take the char array and you put an 'X' in that position. Then you take the Passenger* array and in the same position you assign the address of that client's Passenger object.
The one suggestion I would make is to pass along your airplane structure to your various functions. For example:
switch(ch){
case 1:book(&airplane);
break;
Then, down in your "book" function you would use the airplane structure in your code.
void book(Airplane *airplane){
struct Passenger *p;
FILE *fp;
//struct Airplane airplane; /* Or just remove this line of code */
You might want to repeat the referencing of the airplane structure in your other functions as well.
Hope that helps.
Regards.

C structures displaying numbers rather than user data

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.

Library menu program on C language code not working

In my class i been assigned to make a Library menu program which includes
a structure with bookname/author/price/issue date;
then a menu with different options like addbook,display, search by author etc
i believe i got the basic idea of how to do it and i made a draft of it in codeblocks. but problem is code working but i cant get input/output of book name only (rest working i think) and i cant find the reason why. im a beginner in programming just been doing it for 2 month or so, so i would be very greatful if someone can point out whats wrong in my code.
Thanks in advance and here is my code>
#include<stdio.h>
#include<string.h>
int bookcount=0;
struct library{
char name[100];
char author[100];
float price;
char date[20];
}str[100];
int main(){
int i;
menu();
return 0;
}
int menu(){
int choice,i;
for(i=0;;i++){
printf("\nWelcome to library menu.Please enter a choice from below-");
printf("\n\nPress 1 to add book information\nPress 2 to Display book information\nPress 3 to search books by author name");
printf("\nPress 4 to list the count of books\nPress 5 to find all the books for given price\nPress 0 for exit\nChoice=");
scanf("%d",&choice);
if(choice==0)
break;
else{
switch(choice){
case 1:
addbook();
break;
case 2:
display();
break;
case 3:
searchbyauthor();
break;
case 4:
listcount();
break;
case 5:
findbyprice();
break;
default:
printf("invalid input!\n");
}
}
}
return 0;
}
int addbook(){
int n,i;
printf("\nEnter number of books to add=");
scanf("%d",&n);
for(i=0;i<n;i++){
printf("\nEnter book title=");
gets(str[bookcount].name);
printf("\nEnter book author=");
gets(str[bookcount].author);
printf("\nEnter book date=");
gets(str[bookcount].date);
printf("\nEnter book price=");
scanf("%f",&str[bookcount].price);
bookcount++;
}
return 0;
}
int display(){
int i;
for(i=0;i<bookcount;i++){
printf("\nBook no %d name=",i+1);
puts(str[i].name);
printf("\nBook no %d author=",i+1);
puts(str[i].author);
printf("\nBook no %d issue date=",i+1);
puts(str[i].date);
printf("\nBook no %d price=%f",i+1,str[i].price);
}
return 0;
}
int searchbyauthor(){
char inp[100];
int i;
printf("\nEnter Author name to search=");
gets(inp);
for(i=0;i<bookcount;i++){
if(strcmp(str[i].author,inp)==0)
printf("\nBook name=%s",str[i].name);
}
return 0;
}
int listcount(){
printf("\nnumber of books are =%d\n",bookcount);
return 0;
}
int findbyprice(){
float inp;
int i;
printf("\nEnter price to search=");
scanf("%f",&inp);
for(i=0;i<bookcount;i++){
if(str[i].price==inp)
printf("\nBook name=%s",str[i].name);
}
return 0;
}
As you didn't post any input, I needed to find out that myself, just include sampling input and output next time:
1
1
name
Let's see what your program does with stdin at this point
scanf("%d",&choice); // in menu() in loop, choice := 1, ie add book
scanf("%d",&n); // in addbook(), n := 1, ie. 1 book
gets(str[bookcount].name); // in addbook in loop, this will be and should be ""
scanf() "consume and discard all leading whitespace characters", and newline is whitespace character. So this is what happens:
scanf("%d",&choice); // reads '1' from the input, and stops BEFORE newline
scanf("%d",&n); // discards newline and reads 1 from the input and stops before newline
gets(str[bookcount].name); // because newline is still in buffer and gets
// stops at first newline, this will read empty string
// the next gets will read the `name` from stdin, as it wasn't read already
The fix is rather simple. Just scanf for lines scanf("%d\n",...); not for single variables.

why my program stops working when type enter?

My main goal for this code is to capture the users input and do whatever he wants to do with the choices I have presented, but I'm stuck: when I compile, I can only type the word and the program stops working.
i have no idea where I'm making a mistake.
The is my code:
#include <stdio.h>
#include <string.h>
#define MAX_STRING_LENGTH 100
void grab_user_input(void);
void load_menu(void);
void Count_the_letters(void);
int main(void)
{
grab_user_input();
return 0;
}
void grab_user_input(void)
{
char word;
{
printf("Please enter a single word (25 characters or less): \n");
scanf("%s", &word);
printf("Thanks! The word you entered is: %s\n", word);
}
void load_menu(void)
{
int choice;
do
{
int choice;
printf("\n(:===Menu====:)\n");
printf("1. Count_the_letters\n");
printf("2. Count_the_vowels\n");
printf("3. Reverse_the_word\n");
printf("4. Check_if_palindrome\n");
printf("5. Enter_a_new_word\n");
printf("6. Exit\n");
scanf("%d", &choice);
switch (choice)
{
case 1: Count_the_letters();
break;
}
} while (choice != 3);
}
void Count_the_letters(void)
{
char S[MAX_STRING_LENGTH];
int count;
count = 0;
do {
printf("string:\t");
scanf("%s",S);
if (strcmp(S,"exit") != 0)
++count;
} while (strcmp(S,"exit") != 0);
printf("word count:\t%d\n", count);
}
return 0;
}
scanf("%s", &word);
needs an array of characters to read the data. &word only has space for one character.
You are running into undefined behavior.
Use
char word[26];
scanf("%25s", &word);
The reason is that you are passing the address to the char variable you declared and scanf() is trying to write two bytes where it only fits one.
char word
this declares a char variable, it can hold a single byte
scanf("%s", &word);
whill require at least one byte for an empty string the '\0'.
But also, you declared a lot of functions inside void grab_user_input(void), that is not valid standard c, it might work with some compiler, but it's not standard.

C Struct Array Input

I have the following struct
typedef char String[256];
typedef struct
{
String name;
int year;
float price;
} Book;
Array of Books
int main(int argc, const char * argv[])
{
Book books[5];
for (int i=0; i<5; i++) {
books[i] = inputBook();
}
return 0;
}
inputBook() function
Book inputBook()
{
Book myBook;
//Name
puts("Enter Book Name:");
gets(myBook.name);
//Publishing Year
puts("Enter Book Publishing Year:");
scanf("%i", &myBook.year);
//Price
puts("Enter Book Price:");
scanf("%f", &myBook.price);
return myBook;
}
For some reason the first book input is going well but when trying to input the second book and the second call to inputBook() I can set a book name, it jumps straight to the year import.
What is the problem ?
Thanks!
To correct, replace:
gets(myBook.name);
with:
scanf("%255s", myBook.name); /* 255 as name is 256 chars. */
as scanf() will skip any whitespace characters, but gets() will not. A newline character is considered a whitespace character and there will be a newline remaining in stdin after the price has been entered causing gets() to read the newline and effectively read nothing.
Worth reading: warning:gets function is dangerous
This is because the variable myBook is valid only in the inputBook scope and is destroyed as soon as the function exits.
you should pass the book item you want to initialize as a parameter of your function.
function inputBook()...
void inputBook(Book *ptBook )
{
if( ptBook==NULL )
return;
//Name
puts("Enter Book Name:");
gets(ptBook->name);
//Publishing Year
puts("Enter Book Publishing Year:");
scanf("%i", &ptBook->year);
//Price
puts("Enter Book Price:");
scanf("%f", &ptBook->price);
}
The main function...
int main(int argc, const char * argv[])
{
Book books[5];
for (int i=0; i<5; i++) {
inputBook( &books[i] );
}
return 0;
}
I think you need to flush stdin before next iteration. You have orevious CRLF in your stdin stream.
use fflush(stdin); in the beginning of loop.
Maybe you can try fflush(stdin) before input.
Book inputBook()
{
Book myBook;
fflush(stdin);
// rest of the code
}
#include <stdio.h>
typedef char String[256];
typedef struct
{
String name;
int year;
float price;
} Book;
Book inputBook()
{
Book myBook;
//Name
puts("Enter Book Name:");
getchar();
gets(myBook.name);
//Publishing Year
puts("Enter Book Publishing Year:");
scanf("%i", &myBook.year);
//Price
puts("Enter Book Price:");
scanf("%f", &myBook.price);
return myBook;
}
int main(int argc, const char * argv[])
{
Book books[5];
int i = 0; for (i=0; i<5; i++) {
books[i] = inputBook();
}
return 0;
}

Resources