So I know this is probably me going out on a limb but I am very new to C++ and am having difficulties writing this program. So anyways basically I have this program that is like a simple weather station. It prompts the users to input a name and how many weather histories they would like to store which sets the size of the array. After that they can input values for the weather data, print the current data, and print the ones in the history. But the issue I am having is that when the array is full and the user wants to enter more data it should simply copy all the values of the array over to the left deleting the first value at spot 0 and places new value at end. The weirdest thing is that when I run this and enter a odd number array size like 3 or 1 it works fine like it should and shifts values. But when I run it with an array value the is even like 2 or 4 it crashes. I tried debugging it but could not come across where the mistake is. Any help? Its all sloppy sorry, but I was also forced to declare everything in main and make pointers.
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
void askName(string &weatherString){
int size = 0;
//Asks the user to input a name for weather statation
cout << "Please enter the name of the Weather Station, then press enter." << endl;
getline(cin, weatherString);
size = weatherString.length(); //gets tge length of the string just inputed
//loop is to limit the amount of characters the user can input
while (size >= 31) {
cout << "The maximum characters allowed is 30, please try again.";
cout << "Please enter the name of the Weather Station, then press enter." << endl;
getline(cin, weatherString);
size = weatherString.length(); //gets the amount of charaters from the string
}
}
void arraySize(int &i){
string myString;
loop:
while (cout << "How many histories would you like to store?" << endl && getline(cin, myString) &&
!(stringstream(myString) >> i)) {
cout << "That is an Invalid input, press enter to try again.\n";
cin.clear(); //clears invalid
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discards the
}
if (i <= 0){
cout << "Value needs to be greater than 0, try again." << endl;
goto loop;
}
}
void printWelcome(string &weatherString){
//Once the weather station name is subbmitted it is then printed
cout << "\nWelcome to The " + weatherString + " Weather Station" << endl;
}
int getTemperature(int ¤ttemp, int &i, int temp[], int &n){
string myString;
cout << "\n";
//Tells user to input temperature but checks to make sure it is a valid input
temploop:
while (cout << "Please enter the current temperature (In degrees Fahrenheit), then press enter." << endl && getline(cin, myString) &&
!(stringstream(myString) >> currenttemp)) {
cout << "That is an Invalid input, press enter to try again.\n";
cin.clear(); //clears invalid
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discards the input
}
//If statements makes sure that the user input is in a reasonable range
int maxtemp = 200;
int mintemp = -100;
if (currenttemp > maxtemp){
cout << "You must have melted, try again." << endl;
goto temploop;
}
else if (currenttemp < mintemp){
cout << "You must be frozen, try again." << endl;
goto temploop;
}
if (n < i){
temp[n] = currenttemp;
n++;
}
else{
for (int s = 0; s < n; s++){
temp[s] = temp[s + 1];
}
n = i - 1;
temp[n] = currenttemp;
n++;
}
return currenttemp;
}
void windFunction(int ¤tWindspeed, string &windDirection, int &i, int wind[], string direction[], int &m, int &p){
string myString;
//Asks the user to input windspeed but checks to see if the input is valid
windloop:
while (cout << "Please enter the current wind speed (in MPH), then press enter." << endl && getline(cin, myString) &&
!(stringstream(myString) >> currentWindspeed)) {
cout << "That is an Invalid input, press enter to try again.\n";
cin.clear(); //clears input
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discards the input
}
//Checks to make sure the input is in a reasonable range or goes back to the loop
int minwind = 0;
int maxwind = 300;
if (currentWindspeed > maxwind){
cout << "You must have blown away, try again." << endl;
goto windloop;
}
else if (currentWindspeed < minwind){
cout << "No such thing as negative wind speed, try again." << endl;
goto windloop;
}
//checks to verify that the string value has not been altered from default before placing into arrray
if (m < i){
wind[m] = currentWindspeed;
m++;
}
else{
for (int s = 0; s < m; s++){
wind[s] = wind[s + 1];
}
m = i - 1;
wind[m] = currentWindspeed;
m++;
}
//Asks the user to input the current wind direction and stores it as windDirection. Checks to see if it is a valid input
while (cout << "Please enter the current wind direction in capital letters(N, NE, NW, S, SE, SW, E, W), then press enter." << endl &&
getline(cin, windDirection) && windDirection != "N" && windDirection != "NE" && windDirection != "NW" && windDirection != "S"
&& windDirection != "SE" && windDirection != "SW" && windDirection != "E" && windDirection != "W"){
cout << "That is an Invalid wind direction input, press enter to try again.\n";
cin.clear();
cin.ignore();
}
if (p < i){
direction[p] = windDirection;
p++;
}
else{
for (int s = 0; s < p; s++){
direction[s] = direction[s + 1];
}
p = i - 1;
direction[p] = windDirection;
p++;
}
}
//gets the complete weather input from user
void getWeather(int ¤ttemp, string &windDirection, int ¤tWindspeed, int temp[], int wind[], string direction[], int &i,
int &n, int &m, int &p){
getTemperature(currenttemp, i, temp, n);
windFunction(currentWindspeed, windDirection, i, wind, direction, m, p);
}
void inputMenu(int ¤ttemp, int ¤tWindspeed, string &windDirection, string &weatherString, int temp[], int wind[],
string direction[], int &i, int &n, int &m, int &p);
void printWeather(int ¤ttemp, int ¤tWindspeed, string &windDirection, string &weatherString, int temp[], int wind[],
string direction[], int &i, int &n, int &m, int &p){
//allows user to print the current values for the weather station as long as it has already been inputed
if (currenttemp != NULL && currentWindspeed >= 0 && windDirection.length() != NULL){
cout << "\n";
cout << "The " << weatherString << " " << "Weather Station" << endl;
cout << "Current Temperature: " << currenttemp << " " << "Degrees Fahrenheit" << endl;
cout << "Current Wind Speed: " << currentWindspeed << " MPH" << " " << windDirection << endl;
}
else{
cout << "No data has been inputed yet, please input data then try again." << endl;
inputMenu(currenttemp, currentWindspeed, windDirection, weatherString, temp, wind, direction, i, n, m, p); //No data found so user is sent back to option screen
}
}
void printHistory(int ¤ttemp, int ¤tWindspeed, string &windDirection, string &weatherString, int temp[], int wind[],
string direction[], int &i, int &n, int &m, int &p){
//allows user to print the current values for the weather station as long as it has already been inputed
if (currenttemp != NULL && currentWindspeed >= 0 && windDirection.length() != NULL){
cout << "\n";
cout << "Saved readings are printed newest to oldest" << endl;
cout << "The " << weatherString << " " << "Weather Station:";
for (int a = i - 1; a >= 0; a--){
if (!direction[a].empty()){
cout << "\n";
cout << "Current Temperature: " << temp[a] << " " << "Degrees Fahrenheit" << endl;
cout << "Current Wind Speed: " << wind[a] << " MPH" << " " << direction[a] << endl;
}
}
}
else{
cout << "No data has been inputed yet, please input data then try again." << endl;
inputMenu(currenttemp, currentWindspeed, windDirection, weatherString, temp, wind, direction, i, n, m, p); //No data found so user is sent back to option screen
}
}
void inputMenu(int ¤ttemp, int ¤tWindspeed, string &windDirection, string &weatherString, int temp[], int wind[],
string direction[], int &i, int &n, int &m, int &p){
int finish = 0;
//Loop which asks the user for three options to pick from
while (finish == 0){
cout << "\nPlease select from the from the following number options and press enter:" << endl;
cout << "1. To input a complete weather reading" << endl;
cout << "2. To Print the current weather" << endl;
cout << "3. To Print the weather history" << endl;
cout << "4. To exit the program" << endl;
cout << "\n" << endl;
cout << "Enter your choice here: ";
cin >> finish; //takes input from user
system("CLS"); //clears screen
cin.clear();
cin.ignore();
//switch statement evaluates the user input to different cases
switch (finish) {
case 1:
do {
getWeather(currenttemp, windDirection, currentWindspeed, temp, wind, direction, i, n, m, p); //function to get the input of a complete weather reading
finish = 0; //sends user back to while loop menu
system("CLS");
} while (finish == 1);
break;
case 2:
do{
system("CLS");
printWeather(currenttemp, currentWindspeed, windDirection, weatherString, temp, wind, direction, i, n, m, p);
finish = 0; //sends user back to while loop menu
} while (finish == 2);
break;
case 3:
do{
system("CLS");
printHistory(currenttemp, currentWindspeed, windDirection, weatherString, temp, wind, direction, i, n, m, p);
finish = 0; //sends user back to while loop menu
} while (finish == 3);
break;
case 4: //exits the program
do{
//delete[temp];
//delete[wind];
//delete[direction];
exit(0);
} while (finish == 4);
break;
default:
cout << "Please enter a correct value option." << endl;
finish = 0; //invalid input will send user to the option screen
}
}
}
int main(){
string weatherString;
int currenttemp = NULL;
int currentWindspeed = NULL;
string windDirection;
int i;
int n = 0;
int m = 0;
int p = 0;
int* temp;
int* wind;
string* direction;
askName(weatherString); //runs function to ask for name of station
system("CLS"); //clears the screen
arraySize(i);
temp = new (nothrow) int[i];
wind = new (nothrow) int[i];
direction = new (nothrow)string[i];
system("CLS");
printWelcome(weatherString); //Welcome message saying name of station
inputMenu(currenttemp, currentWindspeed, windDirection, weatherString, temp, wind, direction, i, n, m, p); //text driven menu for user input choices
return 0;
}
You have an off by one error in your copy algorithm, which you have in 2 places.
Here is one of them:
for (int s = 0; s < n; s++){
temp[s] = temp[s + 1];
}
n is the length of the array. When s is equal to n-1 (the last iteration) s+1 will be equal to n, which is beyond the bounds of the array.
Also I would check against i rather than n, as i is supposed to be the length.
To fix this compare against i-1 rather than i. You need to change this in 2 places.
for (int s = 0; s < i - 1; s++){
temp[s] = temp[s + 1];
}
I don't know why it only crashes on even array lengths, maybe something to do with memory alignment (IE maybe it over allocates for the odd length), but accessing and writing to unallocated memory invokes undefined behaviour, so any response is reasonable.
Related
I am making a bookshelf of width size s(1<s<100). Add book id and the book width at the leftmost of the vector. If you add a book which causes the width to be exceeded, then delete the rightmost book until the book to be added can be put on the shelf. In the end, the remaining books on the bookshelf can be added.
The issue I am facing that when var = 'E' the program should display the remaining books on the shelf and then exit that problem and go to a different problem, but when 'E' is entered the remaining books on the shelf will not display, and the program will not exit. I have tried messing with the while loops condition that is nested in the overall while loop.
#include <iostream>
#include <vector>
using namespace std;
struct book{
int id;
int w;
};
int main(){
//std::vector::~vector
//create instance of book
book my_book;
//initialize the placeholders
int s, removed_book, back_width;
char var;
//create the vector
vector<book>shelf;
while(true){
//enter the s value
s = 0;
cout << "enter the s value: " << endl;
cin >> s;
int w_total = 0;
//be able to exit the program
if(s == -1){
return 0;
}
int x = 1;
//while remaining space
while(x!=0){ //need to fix this up
cout << "enter the action(A,R,E): " << endl;
cin >> var >> my_book.id >> my_book.w;
//if A
if(var == 'A'){
//get info about the book
/*
cout << "enter id: " << endl;
cin >> my_book.id;
cout << "width(w): " << endl;
cin >> my_book.w;
*/
w_total += my_book.w;
shelf.insert(shelf.begin(),my_book);
cout << "total width(1): " << w_total << endl;
if(w_total > s){
while(w_total >= s){
//remove the rightmost(back) book
w_total = w_total - shelf.back().w;
cout << "total width(2): " << w_total << endl;
shelf.erase(shelf.end()-1);
}
}
}
//if R
else if(var == 'R'){
//cout << "which book to be removed? : " << endl;
//cin >> removed_book;
removed_book = my_book.id;
for(int i = 0; i < s; i++){
if(shelf[i].id == removed_book){
shelf.erase(shelf.begin()+i);
}
}
}
//if E
else if(var == 'E'){
cout << "remaining books on shelf: " << endl;
for(int i = 0; i < shelf.size(); i++){
if(shelf[i].id!=0){
cout << "id: "<<shelf[i].id << endl;
}
}
//maybe put the display in here?
x = 1;
}
}
//print out the remaining shelf
shelf.clear();
//erase the shelfs(vectors) contents
//increase problem number
}
return 0;
}
Expected output:
10(shelf width)
A 1 3(Add id width)
A 2 5
E
-->PROBLEM 1: 2 1
cin >> var >> my_book.id >> my_book.w is asking the user to enter three things: a character and two integers. You have to enter all three before the action in var will be checked and acted upon.
This is a program that grade user inputs for the questions of Driver's License Exam.
I'm having trouble of validating the user input.
I'd like to accept the [ENTER] key as an invalid input and proceed to my validation rather than just go to an empty line and cannot process to the next question. Purpose is to send out error message and that no input is given and [ENTER] key is not valid input and only accept one more chance to enter valid input which are a/A, b/B, c/C, or d/D. So that is why I'm using if statement here instead of loop.
I tried if (testTakerAnswers[ans] == (or =) '\n') {} but still doesn't solve the problem of newline.
I include curses.h in here hope to use getch() statement from the other post but somehow I can't manage to work in my code with an array instead of regular input.
I'm looking for other methods as well rather than getch()
So should I adjust my bool function, or directly validate input in main() function.
#include <iostream>
#include <iomanip>
#include <string>
#include <cctype>
#include <curses.h>
using namespace std;
const unsigned SIZE = 20; // Number of qns in the test
char testTakerAnswers[SIZE]; //Array to hold test taker's answers
bool validateInput(char);
class TestGrader
{
private:
char answers[SIZE]; // Holds the correct answers // Answer is array
int getNumWrong (char[]);
void missedQuestions (char[]);
public:
void setKey(string); // Initialize object with standard keys
void grade(char[]); // Grades the answers from tester
};
void TestGrader::setKey(string key){
if (key.length()!=SIZE){
cout << "Error in key data.\n";
return;
}
for (unsigned pos = 0; pos < SIZE ; pos ++)
answers [pos] = key [pos];
}
void TestGrader::grade(char test[])
{
int numWrong = getNumWrong(test);
if (numWrong <= 5)
cout << "Congratulations. You passed the exam.\n";
else
cout << "You did not pass the exam. \n";
cout << "You got " << (SIZE-numWrong) << " questions correct. \n";
if (numWrong > 0){
cout << "You missed the following " << numWrong << " questions: \n";
missedQuestions(test);
}
}
int TestGrader::getNumWrong(char test[])
{
int counter = 0;
for (int i = 0; i < SIZE; i++){
if (answers[i] != toupper(testTakerAnswers[i])){
counter++;
}
}
return counter;
}
void TestGrader::missedQuestions(char test[])
{
// cout << testTakerAnswers[i]; This is to print taker's answers
int counter = 0;
for (int i = 0; i < SIZE; i++){
if (answers[i] != toupper(testTakerAnswers[i])){
cout << "\n" << i + 1 << ". Correct answers: " << answers[i];
counter++;
}
}
}
bool validateInput(char ans){ // Only A, B, C, D valid input
if (toupper(ans)!='A' && toupper(ans)!= 'B' && toupper(ans)!='C' && toupper(ans)!= 'D'){
cout << "\n********************WARNING*******************\n";
cout << "Invalid input! Enter only a/A, b/B, c/C, or d/D\n";
return false;
}
if (testTakerAnswers[ans] == '\n'){
return false;
}
return true;
}
int main()
{
const int NUM_QUESTIONS = 20;
string name; //Test taker's name
char doAnother; //Control variable for main processing loop
TestGrader DMVexam; //Create a TestGrader object
DMVexam.setKey("BDAACABACDBCDADCCBDA");
do {
cout << "Applicant Name: ";
getline(cin,name);
cout << "Enter answer for " << name << ".\n";
cout << "Use only letters a/A, b/B, c/C, and d/D. \n\n";
for (int i = 0; i < NUM_QUESTIONS; i++){
// Input and validate it
do{
cout << "Q" << i+1 << ": ";
cin >> testTakerAnswers[i];
if (!validateInput(testTakerAnswers[i])){
cout << "You get one more chance to correct.\nOtherwise, it count as wrong answer.";
cout << "\n*********************************************";
cout << "\nRe-enter: ";
cin >> testTakerAnswers[i];
cout << '\n';
break;
}
}while(!validateInput(testTakerAnswers[i]));
}
//Call class function to grade the exam
cout << "Results for " << name << '\n';
DMVexam.grade(testTakerAnswers);
cout << "\nGrade another exam (Y/N)? ";
cin >> doAnother;
while (doAnother != 'Y' && doAnother != 'N' && doAnother != 'y' && doAnother != 'n'){
cout << doAnother << " is not a valid option. Try Again y/Y or n/N" << endl;
cin >> doAnother;}
cout << endl;
cin.ignore();
}while(doAnother != 'N' && doAnother != 'n');
return 0;
}
Your issue is cin >> testTakerAnswers[i]; cin is whitespace delimited, that means that any whitespace (including '\n') will be discarded. So testTakerAnswers[i] can never be '\n'.
I'm not sure exactly what you want to do, but possibly try
getline(cin,input_string);
then
input_string == "A" | input_string == "B" | ...
So if only the enter key is pressed, input_string will become "".
#include <iostream>
#include <string>
#include <fstream>
#include <iomanip>
using namespace std;
void getInformationKeyBoard(int, string[], int[]);
bool openFile(ifstream &infile, string fileName);
void display(int size, string array[]);
void read2Array(ifstream &infile, int size, string array[]);
void printReport(string name[], int score[], int NumberOfStudent);
int main()
{
const int size = 1024;
string Name[size], scoreFile[size];
int score[size];
int NumberOfStudent;
const int SIZE = 7;
ifstream inFile;
char choice;
cout << "You want to enter your scores by your keyboard (A) or from your input (B): ";
cin >> choice;
if (choice == 'a' || choice == 'A') // It will take information from keyboard
{
cout << "How many students do you want to enter: ";
cin >> NumberOfStudent;
getInformationKeyBoard(NumberOfStudent, Name, score);
printReport(Name, score, NumberOfStudent);
}
else if (choice == 'b' || choice == 'B') // It will take information from file
{
string name;
char again = 'Y';
bool close = false;
cout << "Enter name of file: ";
cin >> name;
openFile(inFile, name);
read2Array(inFile, SIZE, scoreFile);
display(SIZE, scoreFile);
}
else // If you choice is not A,a or B,b
cout << "Your did not follow the right instruction.";
cout << endl << endl;
system("pause");
return 0;
}
// Open file
bool openFile(ifstream &infile, string fileName){
infile.open(fileName);
if (infile)
return true;
return false;
}
void getInformationKeyBoard(int size, string Names[], int scores[]) // Information from keyboard
{
for (int i = 0; i < size; i++)
{
cout << i + 1 << ". Student First Name and Last Name: ";
cin.ignore();
getline(cin, Names[i]);
do
{
cout << i + 1 << ". Enter the score between 1 and 100: ";
cin >> scores[i];
} while (scores[i] > 100 || scores[i] < 0);
}
}
void read2Array(ifstream &infile, int size, string array[]){
int index = 0;
string line;
while (getline(infile, line)){
array[index] = line;
++index;
}
}
// Display array
void display(int size, string array[]){
for (int index = 0; index < size; ++index){
cout << array[index] << endl;
}
}
void printReport(string name[], int score[], int NumberOfStudent)
{
int lowest, highest, mean;
cout << "Enter lowest score: ";
cin >> lowest;
cout << "Enter highest score: ";
cin >> highest;
cout << "Enter mean score: ";
cin >> mean;
cout << "================================================================================";
cout << setw(10) << "Number of scores = " << NumberOfStudent << endl;
cout << setw(10) << "Lowest Score = " << lowest << endl;
cout << setw(10) << "Highest Score = " << highest << endl;
cout << setw(10) << "Mean Score = " << mean << endl;
cout << "Name" << setw(15) << "Score" << setw(15) << "IsLowest" << setw(15) << "IsHighest" << setw(15) << "Mean" << endl;
cout << "-----------------------------------------------------------------" << endl;
cout << name[NumberOfStudent] << endl;
cout << endl;
}
A header statistic section of number of scores, lowest, highest, and mean scores, followed by details for each student - one per line.
I stuck at making output to screen. I want my output look like this
Number of scores = 3
Lowest Score = 82
Highest Score = 92
Mean Score = 87
Name Score IsLowest IsHighest >=Mean
F1 L1 82 Y N N
F2 L2 87 N N Y
F3 L3 92 N Y Y
Perhaps you could pass in a ostream object as a parameter, then replace all occurences of cout in your function with the name of that argument. Then you could run the function twice
printReport(cout, other args);
printReport(outFile, other args);
(Or setup the function to call itself so you don't have to enter cout every time).
The only problem with this method is I see you are grabbing input while inside the function. If you want to use the above method, you'd have to move some things around. Instead, I would setup a different function that takes a string as input and inserts said string to both cout and your file. So rather than having to write
cout<<"hi";
file<<"hi";
You could do
...
functionName("hi", outfile);
...
void functionName(string str, ostream outfile)
{
cout<<str;
outfile<<str;
}
Hope this helps
In general, the following function will work to replicate a console output in a file.
#include <stdarg.h> /* va_list, va_start, va_arg, va_end */
void print(FILE *f, char const *fmt, ...) {
va_list ap;
//Normal console print
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
//Printing to file
if (f != NULL) {
va_start(ap, fmt);
vfprintf(f, fmt, ap);
va_end(ap);
}
}
If you want only console output, simply have
print(NULL, "%d\t%d\n", 1, 100);//include any needed C style formatting here
If you want the console output to be saved to a file, simply pass an appropriate file pointer as the first argument.
FILE *fp = fopen("logfile.txt","a");
print(fp, "%d\t%d\n, 1, 100);//logs the console output to logfile.txt
The console window formatting will be preserved in the text file as well.
I've been assigned by school to create an application that contains a book list with 20 different books in it and build a menu with following options:
(a) List – Display the list in tabular format. Each display should contain an appropriate heading and column captions;
(b) Search – Search for a book record in the list using the ISBN and print the full record for the book;
(c) Delete – Delete an existing book record from the list;
(d) Exit – Stop the program.
Here is the sample of my program:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstring>
#include <cctype>
using namespace std;
typedef struct
{
char code[50];
char author[50];
char name[50];
char edition[50];
char publish[50];
char price[50];
} BOOK_LIST;
void list (BOOK_LIST book[], int rows);
void showBook (BOOK_LIST book[], int rows);
void updateRecord (BOOK_LIST book[], int rows);
void advancedSearch (BOOK_LIST book[], int rows);
int deleteBook (BOOK_LIST book[], int rows);
int searchBook(BOOK_LIST book[], int rows);
int main()
{
ifstream inFile("list.txt");
if(!inFile)
cout << "Error opening input file\n";
else
{
BOOK_LIST books[50];
int index = -1, choice;
inFile.getline(books[++index].code, 50);
while(inFile)
{
if(inFile.peek() == '\n')
inFile.ignore(256, '\n');
inFile.getline(books[index].author, 50);
inFile.getline(books[index].name, 50);
inFile.getline(books[index].edition, 50);
inFile.getline(books[index].publish, 50);
inFile >> books[index].price;
// read next number
inFile >> books[++index].code;
}
inFile.close();
// menu starts
do
{
cout << "Do you want to:\n";
cout << "1. List all books\n";
cout << "2. Get details about a book\n";
cout << "3. Delete a book from the list\n";
cout << "4. Exit\n";
cout << "5. Advanced Search\n";
cout << "Enter choice: ";
cin >> choice;
switch (choice)
{
case 1 : list(books, index);
break;
case 2 : showBook(books, index);
break;
case 3 : updateRecord(books, index);
break;
case 5 : advancedSearch(books, index);
case 4 : break;
default: cout << "Invalid choice\n";
}
} while (choice != 4);
ofstream outFile("list.txt");
if(!outFile)
cout << "Error opening output file, records are not updated.\n";
else
{
for (int i = 0; i < index; i++)
{
outFile << books[i].code << endl;
outFile << books[i].author << endl;
outFile << books[i].name << endl;
outFile << books[i].edition << endl;
outFile << books[i].publish << endl;
outFile << books[i].price << endl;
}
outFile.close();
}
}
return 0;
}
void list(BOOK_LIST book[], int rows)
{
cout << fixed << setprecision(2);
cout << "ISBN\t Author BookName Edition\tPublisher\t Price\n";
for (int i = 0; i < rows; i++)
cout << book[i].code << "\t" << book[i].author << "\t"
<< book[i].name << "\t" << book[i].edition << "\t"
<< book[i].publish << "\t"
<< " " << book[i].price << endl;
return;
}
int searchBook(BOOK_LIST book[], int rows)
{
int i = 0;
bool found = false;
char code[50];
cout << "Enter an ISBN code of a book to search: ";
fflush(stdin);
cin.getline(code, 50);
while (i < rows && !found)
{
if (strcmp(code, book[i].code) == 0)
found = true;
else
i++;
}
if (found)
return i;
else
return -1;
}
void showBook(BOOK_LIST book[], int rows)
{
int pos = searchBook(book, rows);
if (pos != -1)
{
cout << "Author is " << book[pos].author << endl;
cout << "Book name is "<< book[pos].name << endl;
cout << book[pos].edition << " Edition" << endl;
cout << "The publisher of this book is " << book[pos].publish << endl;
cout << "Current price is " << book[pos].price << endl;
}
else
cout << "Product not found\n";
return;
}
void updateRecord(BOOK_LIST book[], int rows)
{
int pos = deleteBook(book, rows);
char code [50];
int i,j = 0;
for(i = 0; i < rows ; i++)
{
if(strcmp(code, book[i].code))
{
strcpy(book[j].code , book[i].code);
strcpy(book[j].author, book[i].author);
strcpy(book[j].name, book[i].name);
strcpy(book[j].edition, book[i].edition);
strcpy(book[j].publish, book[i].publish);
strcpy(book[j].price, book[i].price);
j++;
}//if
else
{
i++;
strcpy(book[j].code, book[i].code);
strcpy(book[j].author, book[i].author);
strcpy(book[j].name, book[i].name);
strcpy(book[j].edition, book[i].edition);
strcpy(book[j].publish, book[i].publish);
strcpy(book[j].price, book[i].price);
j++;
}//else
}//for
return;
}
int deleteBook (BOOK_LIST book[], int rows)
{
int i = 0;
bool found = false;
char code[50];
cout << "Enter an ISBN code of a book to delete: ";
fflush(stdin);
cin.getline(code, 50);
while (i < rows && !found)
{
if (strcmp(code, book[i].code) == 0)
found = true;
else
i++;
}
if (found)
return i;
else
return -1;
}
void advancedSearch (BOOK_LIST book[], int rows)
{
char advanced[50];
cout << "Please enter either the author's name or the book name to search: ";
fflush(stdin);
cin.getline(advanced, 50);
for(int i = 0; i < rows; i++)
{
if(strstr(book[i].author, advanced) || strstr(book[i].name, advanced))
{
cout << "ISBN is " << book[i].code << endl;
cout << "Author is " << book[i].author << endl;
cout << "Book name is " << book[i].name << endl;
cout << book[i].edition << " Edition" << endl;
cout << "Publisher is " << book[i].publish << endl;
cout << "Current price is " << book[i].price << endl;
}
}
return ;
}
The problem starts here:
When I want to permanently delete a whole row of book record. But the book record is still there after deleting.
First, this is my menu, then I press 1 to check the list for the IBSN. Then, I press 3 to proceed to the deleting part. At that time, I choose TheHost to delete. After the deleting, to ensure that I have deleted the chosen book, so I press 1 to check the list again, but unfortunately the book is still there:
If I am able to delete a book record, and how do I delete a record permanently? And after deleting a record, how do I move the remaining records upwards, so that it won't leave any empty row there?
The function for the deleting:
void updateRecord(BOOK_LIST book[], int rows)
{
int pos = deleteBook(book, rows);
char code [50];
int i,j = 0;
for(i = 0; i < rows ; i++)
{
if(strcmp(code, book[i].code))
{
strcpy(book[j].code , book[i].code);
strcpy(book[j].author, book[i].author);
strcpy(book[j].name, book[i].name);
strcpy(book[j].edition, book[i].edition);
strcpy(book[j].publish, book[i].publish);
strcpy(book[j].price, book[i].price);
j++;
}//if
else
{
i++;
strcpy(book[j].code, book[i].code);
strcpy(book[j].author, book[i].author);
strcpy(book[j].name, book[i].name);
strcpy(book[j].edition, book[i].edition);
strcpy(book[j].publish, book[i].publish);
strcpy(book[j].price, book[i].price);
j++;
}//else
}//for
return;
}
The Text file that I used in this program a.k.a the BOOK_LIST
I see (at least) two problems with your code around deleting a book.
in update_record you're using a char code[50] which is being used to compare with strcmp later on but is not initialized.
when you delete a book you should update your index which becomes rows in the update_record method. However index is passed to rows by value which means that even if you try running --rows; in update_record it won't decrement index. You'll need to pass it by reference for it to update index.
On a side note, I agree with comments regarding fixing your code to use vectors/maps & strings instead of simple arrays and char*.
But since you mentioned it was a school task I would guess you haven't reached that sort of material yet.
Good Luck.
The assignment most probably expects you to use std::list template rather than the classical C array. Insertion and deletion is natural for lists.
An alternative would be to use std:map using the ISBN as a key. ISBN is supposed to be globally unique.
Just to expand on my comment, here is one way to remove an element from an array.
Suppose we have an array of char called X, containing {'a', 'b', 'c', 'd', 'e', 'f'}, and we want to get rid of 'c'.
If we want to maintain the order of the remaining elements, then what we're aiming for is {'a', 'b', 'd', 'e', 'f'}. So we copy the 'd' into the 'c' place, the 'e' into the old 'd' place, and so on:
a b c d e f
a b d d e f
a b d e e f
a b d e f f
We can do this with code like
for(int k=2; k<5; ++k)
X[k] = X[k+1];
And what happens to that extra 'f' at the end? We could write some placeholder into that unwanted space, and then watch out for that placeholder for the rest of the run. Or, we could just stop using that space, and say that from now on we're considering an array of length 5. That extra 'f' will still be there, but for now we don't care about what exists past the end of our array.
(If we don't care about the order of the remaining elements, then we can make this a lot simpler.)
Remember, it's always easier to develop new functionality in isolation.
Once you have this working, you can apply it in your code and get a passing grade, but if you really want to learn something useful you should write a Book class.
Prompt:
Convert the functions theSmallest() and fill_array()to template functions.
Test your template functions with 3 different data types: int, float and char.
Problem:
When I load this into the compiler, there are no errors. It works for INT and Float; however when I run the index_of_smallest function for the character option... it doesn't like it. When I actually check with a "cout" what the value for min is during a char call, it is giving me "-10002e89..". That value never changes so in the for loop the index_of_min is always 0 so the compiler thinks that the smallest character is always at the index of 0.
CODE:
#include <iostream>
#include <cstdlib>
using namespace std;
const int DECLARED_SIZE = 20;
template <class BaseType>
int index_of_smallest(BaseType a[], int size, int& number_used)
{
BaseType min = a[0];
int index_of_min = 0;
cout << index_of_min<< endl;
for (int index = 1 ; index < number_used; index++)
{
if (a[index] < min)
{
min = a[index];
index_of_min = index;
}
}
cout << index_of_min<< endl;
return index_of_min;
}
template <class BaseType>
void fill_array(BaseType a[], int size, int& number_used)
{
int index = 0;
BaseType ans;
cout << "Enter up to " << size << " of the Data Type selected.\n"
<< "Mark the end of a list of numbers with a negative number.\n"
<< "Mark the end of a list of characters with the negative symbol \"-\". \n"
<< "Separate each input with a space. \n" << endl;
cin >> ans;
while (ans >= 0 && ans != '-')
{
a[index] = ans;
index++;
cin >> ans;
}
number_used = index;
}
void menu()
{
int number_used, choice, smallest, result;
int start_index = 0;
char menuLoop = 'Y';
while (toupper(menuLoop) == 'Y')
{
cout << "Please select a type of Input: \n"
<< "1. Integers (1, 2, 3, 4, etc..)\n"
<< "2. Decimals (1.0, 2.0, 3.0. 4.0, etc..)\n"
<< "3. Characters ( a, b, c, d, etc...)\n\n\n";
cin >> choice;
switch (choice)
{
case 1:
int arrI[DECLARED_SIZE];
system ("CLS");
fill_array(arrI, DECLARED_SIZE, number_used);
smallest = index_of_smallest(arrI, start_index, number_used);
cout << "The smallest integer is: " << arrI[smallest] << " ";
break;
case 2:
float arrF[DECLARED_SIZE];
system ("CLS");
fill_array(arrF, DECLARED_SIZE, number_used);
smallest = index_of_smallest(arrF, start_index, number_used);
cout << "The smallest float is: "<< arrF[smallest] << " ";
break;
case 3:
char arrC[DECLARED_SIZE];
system ("CLS");
fill_array(arrC, DECLARED_SIZE, number_used);
smallest = index_of_smallest(arrF, start_index, result);
cout << "The smallest character is: " << arrC[smallest] <<" \n";
break;
default:
cout << "That is an invalid choice! Exiting Program";
}
cout << "\n\nWould you like to return to the main menu? (Y/N): ";
cin >> menuLoop;
while(toupper(menuLoop) != 'Y' && toupper(menuLoop) != 'N')
{
cout << "Invalid Choice: Please type (Y/N): ";
cin >> menuLoop;
}
system("CLS");
}
}
int main()
{
using namespace std;
menu();
system("PAUSE");
}
Your error is here:
smallest = index_of_smallest(arrF, start_index, result);
Which should be:
smallest = index_of_smallest(arrC, start_index, number_used);
You were using the wrong array, and you were passing result (which was never initialized) instead of number_used.