I am trying to practice the multiple file project (creating .cpp files and also .h files) and functions together.I have some functions for different kinds of shapes which is in different .cpp files and a .h file (my Functions.h) with the prototypes of those functions. I created another .cpp file (tools.cpp) where I have all bunch of functions (such as- getInt, getFloat, getBool, getBoundedInt, getWidth etc) so that I can also use that one in my other projects as well and also for that tools.cpp file. I have tools.h file with the prototypes.
Now, I want to make another function (allFunctionController) which will handle all these different kinds of function (like- taking user input, checking input valid or invalid, help function for user, call the shape functions etc). And, there would be another function to allow user to repeat all these things and my main function will only call this one. The screenshot that I provided would be more clear to understand.
[screenshot]
tools.cpp :-
// Tools.cpp
#include"Tools.h"
#include<string>
#include<iostream>
using namespace std;
namespace tools
{
int width( int value )
{
bool isNegative = value < 0;
int spaceForSign;
if ( isNegative )
{
spaceForSign = 1;
value = -value;
}
else
spaceForSign = 0;
int digitCount = 0;
int digits = value;
do
{
// pull one digit off and count it;
++digitCount;
// if I wanted to look at the digit before throwing away:
int digit = digits % 10;
digits = digits / 10; // remove one digit
} while ( digits > 0 );
return digitCount;
}
char getChar(string prompt)
{
while (true)
{
char userInput;
cout << prompt;
cin >> userInput;
cin.ignore(999,'\n');
if ( !cin.fail() ) return userInput;
cin.clear();
cin.ignore(999,'\n');
cout << "try again" << endl;
}
}
int getInt(string prompt)
{
while (true)
{
int userInput;
cout << prompt;
cin >> userInput;
cin.ignore(999,'\n');
if ( !cin.fail() ) return userInput;
cout << "input failure, try again";
cin.clear();
cin.ignore(999,'\n');
}
}
int getBoundedInt( string prompt, int lowBound, int highBound )
{
while (true)
{
int userInput = getInt(prompt);
if ( lowBound <= userInput && userInput <= highBound )
return userInput;
cout << "must be in range " << lowBound << " to "
<< highBound << ", try again" << endl;
}
}
float getFloat(string prompt)
{
while (true)
{
float userInput;
cout << prompt;
cin >> userInput;
cin.ignore(999,'\n');
if ( !cin.fail() ) return userInput;
cout << "input failure, try again";
cin.clear();
cin.ignore(999,'\n');
}
}
string getString(string prompt)
{
while (true)
{
string userInput;
cout << prompt;
cin >> userInput;
cin.ignore(999,'\n');
if ( !cin.fail() ) return userInput;
cout << "input failure, try again";
cin.clear();
cin.ignore(999,'\n');
}
}
string getLine(string prompt)
{
while (true)
{
string userInput;
cout << prompt;
getline(cin, userInput);
if ( !cin.fail() ) return userInput;
cout << "input failure, try again";
cin.clear();
cin.ignore(999,'\n'); // whatever caused fail
}
}
bool isLowerCase( char c )
{
return 'a' <= c && c <= 'z';
}
bool isUpperCase( char c )
{
return 'A' <= c && c <= 'Z';
}
bool isLetter( char c )
{
return isLowerCase(c) || isUpperCase(c);
}
char getLetter(string prompt)
{
while (true)
{
char userInput = getChar(prompt);
if ( isLetter(userInput) )
return userInput;
cout << "letters only, please" << endl;
}
}
bool getBool(string prompt)
{
while (true)
{
switch ( getChar(prompt) )
{
case 'y': case 'Y': return true;
case 'n': case 'N': return false;
}
cout << "y or n please" << endl;
}
}
}
tools.h:-
// Tools.h
#ifndef TOOLS_LOCK
#define TOOLS_LOCK
#include<string>
namespace tools
{
int getInt(std::string prompt);
int width( int value );
char getChar(std::string prompt);
int getInt(std::string prompt);
int getBoundedInt( std::string prompt, int lowBound, int highBound );
float getFloat(std::string prompt);
std::string getString(std::string prompt);
std::string getLine(std::string prompt);
bool isLowerCase( char c );
bool isUpperCase( char c );
bool isLetter( char c );
char getLetter(std::string prompt);
bool getBool(std::string prompt);
}
#endif
My functions.h:-
// My functions.h
namespace myFunctions
{
void allFunctionController ();
void solidRectangle (int size);
void hollowRectangle (int userChoiceOfSize);
void solidTriangleFacingNorthEast (int size);
void hollowTriangleFacingNorthEast (int size);
void solidTriangleFacingSouthWest (int size);
void hollowTriangleFacingSouthWest (int size);
}
I am only adding here the hollow and solid rectangle code. But there are more shape function in my project.
hollowRectangle.cpp:-
#include"My functions.h"
#include<iostream>
using namespace std;
namespace myFunctions
{
void hollowRectangle (int size)
{
int row, column;
for (row = 1; row <= size; row++)
{
if (row > 1 && row < size)
{
cout << "*";
for (column = 2; column < size; column++)
{
cout << ' ';
}
cout << "*";
}
else
{
for (column = 1; column <= size; column++)
{
cout << "*";
}
}
}
cout << endl;
cout << endl;
cout << "Please press enter to finish...";
cin.ignore(999,'\n');
return;
}
}
solidRectangle.cpp:-
// Program for the solid rectangle
#include"My functions.h"
#include<iostream>
using namespace std;
namespace myFunctions
{
int solidRectangle (int size)
{
int row, column;
for (row = 1; row <= size; row++)
{
for (column = 1; column <= size; column++)
{
cout << "*";
}
cout << endl;
}
cout << endl;
cout << "Please press enter to finish...";
cin.ignore(999,'\n');
return 0;
}
}
allFunctionController:- I screwed up here.
// This function will control all other functions.
#include"My functions.h"
#include"Tools.h"
#include<iostream>
using namespace std;
void allFunctionController ()
{
using namespace tools;
{
int size = getBoundedInt ("Please enter the size", 1, 75);
}
}
using namespace myFunctions;
{
void getHelp ()
{
int size,userInput;
cin >> userInput;
switch (userInput)
{
case 1:
solidRectangle (size);
}
}
}
I want to know how to handle all these header files and use the function in my allFunctionController function.
I didn't write my main function yet. Please let me know if there is anything wrong in my posting either code or attachment. Thanks in advance.
Related
I'm sorry for the vague title, but I don't know what else to say.
Here is my program:
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
int
main (int argc, char **argv)
{
//string fin;
string ttl, dscp, ext;
string west = "w";
string east = "e";
string north = "n";
string south = "s";
int numRooms;
//string argv[1] = filename;
class Room
{
public:string title;
string description;
string exits;
int exitWest = -1;
int exitNorth = -1;
int exitEast = -1;
int exitSouth = -1;
int numExits;
};
ifstream fin;
fin.open (argv[1]);
//cin.ignore();
int t = 0;
while (fin)
{
string tilde;
string tester;
tester = "~";
cin >> tilde;
if (tilde == tester)
{
t = t + 1;
}
(numRooms = t / 3);
}
Room *roomArrayPtr = new Room[numRooms];
fin.clear ();
while (fin)
{
for (int l = 0; l < numRooms; l++)
{
getline (fin, ttl, '~');
roomArrayPtr[l].title = ttl;
getline (fin, dscp, '~');
roomArrayPtr[l].description = dscp;
getline (fin, ext, '~');
stringstream sin;
sin << ext;
string x;
int y;
while (sin >> x >> y)
{
if (x == west)
{
roomArrayPtr[l].exitWest = y;
}
if (x == south)
{
roomArrayPtr[l].exitSouth = y;
}
if (x == north)
{
roomArrayPtr[l].exitNorth = y;
}
if (x == east)
{
roomArrayPtr[l].exitEast = y;
}
}
sin.clear ();
int numext;
numext = (ext.size ()) / 3;
roomArrayPtr[l].numExits = numext;
}}
//(read in file again populate roomarrayptr w while loop and getline)
//roomArrayPtr[index].title = line;
//roomArrayPtr[index].description=line;
//close files, while loop that reads in user input from stdin, delete pointers w (delete[] roomArrayPtr;)
//if (exitsarray[i].size() > 2){
char command;
char newcommand;
cout << ">";
cin >> command;
int currentroom = 0;
int newroom;
bool keepgoing = true;
//string dir1;
while (keepgoing)
switch (command)
{
// stringstream ss;
case 'l':
cout << roomArrayPtr[currentroom].title << endl;
cout << roomArrayPtr[currentroom].description << endl;
cout << endl;
//if (roomArrayPtr[currentroom].numExits < 2) {
cout << "Exits: ";
if (roomArrayPtr[currentroom].exitWest > -1)
{
cout << "w";
}
if (roomArrayPtr[currentroom].exitNorth > -1)
{
cout << "n";
}
if (roomArrayPtr[currentroom].exitSouth > -1)
{
cout << "s";
}
if (roomArrayPtr[currentroom].exitEast > -1)
{
cout << "e";
}
/*else {
cout << "Exits: " ;
for (int k = 0; k < numExits; k++){
cout << exitdirection << " ";
}
}*/
//string newcommand;
cin >> newcommand;
//int newroom;
switch (newcommand)
{
case 'w':
if (roomArrayPtr[currentroom].exitWest == -1)
{
cout << "You can't go WEST!" << endl;
}
else
{
newroom = roomArrayPtr[currentroom].exitWest;
cout << "You moved WEST." << endl;
}
break;
case 'e':
if (roomArrayPtr[currentroom].exitEast == -1)
{
cout << "You can't go EAST!" << endl;
}
else
{
newroom = roomArrayPtr[currentroom].exitEast;
cout << "You moved EAST." << endl;
}
break;
case 'n':
if (roomArrayPtr[currentroom].exitNorth == -1)
{
cout << "You can't go NORTH!" << endl;
}
else
{
newroom = roomArrayPtr[currentroom].exitNorth;
cout << "You moved NORTH." << endl;
}
break;
case 's':
if (roomArrayPtr[currentroom].exitSouth == -1)
{
cout << "You can't go SOUTH!" << endl;
}
else
{
newroom = roomArrayPtr[currentroom].exitSouth;
cout << "You moved SOUTH." << endl;
}
break;
}
break;
case 'q':
keepgoing = false;
return 0;
break;
currentroom = newroom;
}
}
Whenever I run it, it compiles, but nothing happens. I tried putting in some random cout << "testing1" "testing2" scattered throughout, but none of those even showed up. I put it immediately after the { after int main and it still didn't show up. What's going on?
I tried putting in some random cout << "testing1" "testing2" scattered throughout, but none of those even showed up. I put it immediately after the { after int main and it still didn't show up.
you are reading the wrong file
int t = 0;
while (fin)
{
string tilde;
string tester;
tester = "~";
cin >> tilde; <<<<===== i assume you mean fin
if (tilde == tester)
{
t = t + 1;
}
(numRooms = t / 3);
}
I have been trying to get this to work for an hour now and I know it can't be that difficult a fix. Every time I enter the file.txt name it comes up as invalid file. I tried moving the files to the same directory as the .cpp file and everything but I just cant get it to read. Help would be appreciated.
#include<iostream>
#include<iomanip>
#include<fstream>
#include<string>
#include<assert.h>
using namespace std;
const int SIZE = 20;
void readIntFile(ifstream& x, int intArray[], int size, int &length);
void printValues(int intArray[], int& length);
char getSentinel();
int main()
{
ifstream inputStream;
const int size = SIZE;
string fileName;
int length = 0;
bool isEmpty = false;
int intArray[size];
char sentinel = 'y';
while (sentinel == 'y' || sentinel == 'Y')
{
cout << "Please enter the name of the file: ";
cin >> fileName;
inputStream.open(fileName);
if (inputStream.bad() || inputStream.fail())
{
cout << "Error, <" << fileName << "> is Invalid File Name.";
}
if (fileName.empty())
{
isEmpty = true;
}
if (isEmpty == true)
{
cout << "Error <" << fileName << "> has no data.";
}
if (inputStream.good() && isEmpty == false)
{
readIntFile(inputStream, intArray, size, length);
printValues(intArray, length);
inputStream.close();
}
sentinel = getSentinel();
}
return 0;
}
void readIntFile(ifstream& x, int intArray[], int size, int& length)
{
int count = 0;
int arrayLocation = -1;
int fileInputValue = 0;
x >> fileInputValue;
while (!x.eof())
{
count ++;
if (count > SIZE)
{
cout << "The file has more than <" << SIZE << "> values." << endl;
break;
}
else
{
arrayLocation ++;
intArray[count] = fileInputValue;
x >> fileInputValue;
}
}
}
void printValues(int intArray[], int& length)
{
assert(length > 0);
cout << "<" << length << "> values processed from the file. The values are: ";
for (int i=0; i <= length; i++)
{
cout << intArray[i] << ", ";
}
}
char getSentinel()
{
char userInput = 'n';
bool inputCheck = false;
cout << "Do you wish to process another file (y/n)?" << endl;
cin >> userInput;
do
{
if (userInput == 'y' || userInput == 'Y' || userInput == 'n' || userInput == 'N')
{
inputCheck = true;
}
else
{
cout << "Invalid response: <" << userInput << ">" << endl;
cout << "Do you wish to process another file (y/n)?" << endl;
cin >> userInput;
}
} while (!inputCheck);
return userInput;
}
Your basic problem is in function
void readIntFile(ifstream& x, int intArray[], int size, int& length)
You do not set the output variable length. And you use the wrong index value for your array. Please check.
Additionally there are many other problems in your code.
I will now paste your code, amended with my comments comments, where problems are or where things should be improved.
Please see:
#include<iostream>
#include<iomanip>
#include<fstream>
#include<string>
#include<assert.h>
using namespace std; // Should never be used. Always use fully qualified names
const int SIZE = 20; // Please use constexpr
// Do not use C-Style function prototypes. Put main at the bottom
// Do not use C-Style Arrays
// In C++ (C-Style-)Arrays are different. You actually do not pass an array to your function
// but a decyed pointer. You can pass an array by pointer or by reference, but this has a different syntax
void readIntFile(ifstream& x, int intArray[], int size, int &length);
void printValues(int intArray[], int& length);
char getSentinel();
int main()
{
// All variables shall be initialized at the point of defintion
ifstream inputStream; // You should define variables just before you need then
const int size = SIZE; // This is code duplication. And constexpr should be used
string fileName;
int length = 0;
bool isEmpty = false;
int intArray[size]; // C-Style Arrays should not be used. Use std::array or best, std::vector
char sentinel = 'y'; // You could use universal initializer syntax with braced initializer
while (sentinel == 'y' || sentinel == 'Y')
{
cout << "Please enter the name of the file: ";
cin >> fileName;
inputStream.open(fileName); // The constructor can open the file for you
if (inputStream.bad() || inputStream.fail()) // This is too complicated
{
cout << "Error, <" << fileName << "> is Invalid File Name.";
}
if (fileName.empty()) // Check is too late and not necessary
{
isEmpty = true;
}
if (isEmpty == true)
{
cout << "Error <" << fileName << "> has no data.";
}
if (inputStream.good() && isEmpty == false)
{
readIntFile(inputStream, intArray, size, length);
printValues(intArray, length);
inputStream.close(); // Destructor will clsoe the file for you
}
sentinel = getSentinel();
}
return 0;
}
// Not optimal function prototype
void readIntFile(ifstream& x, int intArray[], int size, int& length)
{
// the whole design / logic is very strange
int count = 0;
int arrayLocation = -1; // More then strange. Shows that this is a bad design
int fileInputValue = 0;
x >> fileInputValue;
while (!x.eof()) // Bad or even wrong design
{
count ++; // Wrong. See below. array will be filled with starting with index one
if (count > SIZE)
{
cout << "The file has more than <" << SIZE << "> values." << endl;
break;
}
else
{
arrayLocation ++; // This variable is not used
intArray[count] = fileInputValue;
x >> fileInputValue;
}
}
// Nobody will set the length variable
}
void printValues(int intArray[], int& length)
{
assert(length > 0); // Basically OK, but no necessary here. Cannoz happen
cout << "<" << length << "> values processed from the file. The values are: ";
for (int i=0; i <= length; i++)
{
cout << intArray[i] << ", ";
}
// There is now newline character used anywhere
}
// Very complicated
char getSentinel()
{
char userInput = 'n';
bool inputCheck = false;
cout << "Do you wish to process another file (y/n)?" << endl;
cin >> userInput;
do
{
if (userInput == 'y' || userInput == 'Y' || userInput == 'n' || userInput == 'N')
{
inputCheck = true;
}
else
{
cout << "Invalid response: <" << userInput << ">" << endl;
cout << "Do you wish to process another file (y/n)?" << endl;
cin >> userInput;
}
} while (!inputCheck);
return userInput;
}
Next, I will make your code working, by fixing the biggest problems. I will still follow your programming style.
#include<iostream>
#include<iomanip>
#include<fstream>
#include<string>
#include<assert.h>
constexpr int MaxArraySize = 20;
using IntArray = int[MaxArraySize];
void readIntFile(std::ifstream& x, int intArray[], int& length)
{
length = 0;
int value{};
while (x >> value)
{
if (length >= MaxArraySize)
{
std::cout << "The file has more than <" << MaxArraySize << "> values.\n";
break;
}
else
{
intArray[length++] = value;
}
}
}
void printValues(int intArray[], int& length)
{
std::cout << "\n<" << length << "> values processed from the file. The values are: ";
for (int i=0; i < length; i++)
{
std::cout << intArray[i] << ", ";
}
std::cout << "\n\n";
}
bool getSentinel()
{
char userInput{'n'};
bool valid = false;
while (not valid)
{
std::cout << "\n\nDo you wish to process another file (y/n)?\n";
std::cin >> userInput;
if (userInput != 'y' && userInput != 'Y' && userInput != 'n' && userInput != 'N')
{
std::cout << "Invalid response: <" << userInput << ">\n\n";
}
else {
valid = true;
}
}
return ( userInput=='y' || userInput=='Y');
}
int main()
{
int intArray[MaxArraySize];
bool sentinel = true;
while (sentinel)
{
std::cout << "Please enter the name of the file: ";
std::string fileName{};
std::cin >> fileName;
if (fileName.empty())
{
std::cout << "Error <" << fileName << "> has no data.\n\n";
}
else {
std::ifstream inputStream(fileName);
if (!inputStream)
{
std::cout << "Error, <" << fileName << "> is Invalid File Name.\n\n";
}
else
{
int length = 0;
readIntFile(inputStream, intArray, length);
printValues(intArray, length);
}
}
sentinel = getSentinel();
}
return 0;
}
and, in the end, because we are in a C++ site here, I will show (one of many possible) a more advanced C++ solution.
This is just for information and to grab some ideas for the future
#include<iostream>
#include<iomanip>
#include<fstream>
#include<string>
#include<vector>
#include<algorithm>
#include<iterator>
#include<initializer_list>
// Some aliases for easier reading and saving typing work
using DataType = int;
using Vector = std::vector<DataType>;
// Define an "in" operator
struct in {
in(const std::initializer_list<char>& il) : ref(il) {}
const std::initializer_list<char>& ref;
};
bool operator,(const char& lhs, const in& rhs) {
return std::find(rhs.ref.begin(), rhs.ref.end(), lhs) != rhs.ref.end();
}
int main() {
// As long as the user wants to read files
for (bool userWantsToContinue{true}; userWantsToContinue;) {
std::cout << "\nPlease enter a valid filename: ";
if (std::string filename{}; std::cin >> filename) {
// Open the file for reading and check, it it is open
if (std::ifstream inputStream{filename}; inputStream) {
// Read all data from the file
Vector data(std::istream_iterator<DataType>(inputStream), {});
// Now show result to user
std::cout << "\nRead values are:\n";
std::copy(data.begin(), data.end(), std::ostream_iterator<DataType>(std::cout, " "));
}
else std::cerr << "\nError: Could not open file '" << filename << "' for reading\n\n";
}
else std::cerr << "\nError: Problem with filename input\n\n";
// Ask, if the user wants to continue
bool validInput{false};
while (not validInput) {
std::cout << "\n\nDo you want to read more files? Please enter 'y' or 'n' ";
if (char selection{}; (std::cin >> selection) && (selection, in{'y','Y','n','N',}) ) {
validInput = true;
userWantsToContinue = (selection, in{'y','Y'});
}
else {
std::cout << "\n\nInvalid input, please retry\n\n";
}
}
}
return 0;
}
Try using an full absolute filename, not a relative one.
And replace cin >> fileName; with std::getline(std::cin, fileName); Otherwise, it will easily break. The getline version is much more robust.
If this was not enough, read the answer of: How do I get the directory that a program is running from? and do the checks suited for your system to find out your "working directory". This is the place where you input file must be, if you don't use absolute paths.
Only problems remaining now are that my choice while loop is infinite since the break statements dont seem to be breaking out of the loop at all, so the program doesn't read the answer loop. Also, "Invalid Entry" displays every other incorrect input instead of displaying everytime an invalid character is entered
#include <iostream>
#include <cctype>
using namespace std;
int getAges(int age, const int SIZE);
char getChoice();
void displayInOrder(int numbers[], const int SIZE, char choice);
void displayInReverse(int numbers[], const int SIZE, char choice);
int main()
{
const int SIZE = 5;
int numbers[SIZE] = { 1, 2 ,3 ,4, 5 };
char answer = 0;
int age = 0;
char choice = 0;
while (choice = getChoice())
{
if (toupper(choice) == 'O')
{
displayInOrder(numbers, SIZE, choice);
break;
}
else if (toupper(choice) == 'R')
{
displayInReverse(numbers, SIZE, choice);
break;
}
else
{
cout << "Invalid entry! - Must be O or R\n\n";
break;
}
}
while (toupper(answer) == 'Y')
{
system("cls");
age = getAges(age, SIZE);
choice = getChoice();
displayInOrder(numbers, SIZE, choice);
displayInReverse(numbers, SIZE, choice);
cout << "Run program again (Y or N)? ";
cin >> answer;
if (toupper(answer) == 'N')
{
exit();
}
}
return 0;
}
int getAges(int age, const int SIZE)
{
cout << "Enter " << SIZE << " ages: \n\n";
cin >> age;
cout << endl;
cin >> age;
cout << endl;
cin >> age;
cout << endl;
cin >> age;
cout << endl;
cin >> age;
cout << endl;
return age;
}
char getChoice()
{
char choice;
cout << "How do you want to see the ages displayed? \n\n Enter O for In Order, or R for In Reverse.\n\n";
cin >> choice;
return choice;
}
void displayInOrder(int numbers[], const int SIZE, char answer)
{
cout << "Here are the ages in order: \n\n";
for (int i = 0; i < SIZE; i++)
{
cout << numbers[i] << endl;
}
}
void displayInReverse(int numbers[], const int SIZE, char answer)
{
cout << "Here are the ages in reverse order: \n\n";
for (int i = SIZE - 1; i >= 0; i--)
{
cout << numbers[i] << endl;
}
}
1."Invalid Entry" displays every other incorrect input: you have a getChoice() call inside the while loop, here:
else
{
cout << "Invalid entry! - Must be O or R\n\n";
choice = getChoice();
}
which is followed by a getChoice() call in the
while (choice = getChoice())
Hence the previous getChoice() is not processed.
2."I'm not sure how to close the program if the user enters N for answer", You should think about if you can ever reach the second while loop and where you are setting the answer variable or basically where you are taking the user input for ending the program? You should see if it can it be taken care of in the first while loop ?
I don't understand why getAges is being skipped.
#include <iostream>
#include <cctype>
using namespace std;
int getAges(int age, const int SIZE);
char getChoice();
void displayInOrder(int numbers[], const int SIZE, char choice);
void displayInReverse(int numbers[], const int SIZE, char choice);
int main()
{
const int SIZE = 5;
int numbers[SIZE] = { 1, 2 ,3 ,4, 5 };
char answer;
int age;
char choice;
if (toupper(choice) == 'O')
{
displayInOrder(numbers, SIZE, choice);
}
else if (toupper(choice) == 'R')
{
displayInReverse(numbers, SIZE, choice);
}
else
{
cout << "Invalid entry! - Must be O or R\n\n";
}
if (toupper(answer) == 'Y')
{
system("cls");
age = getAges(age, SIZE);
choice = getChoice();
displayInOrder(numbers, SIZE, choice);
displayInReverse(numbers, SIZE, choice);
cout << "Run program again (Y or N)? ";
cin >> answer;
break;
}
else if (toupper(answer) == 'N')
{
return 0;
}
return 0;
}
int getAges(int age, const int SIZE)
{
cout << "Enter " << SIZE << " ages: \n\n";
cin >> age;
cout << endl;
cin >> age;
cout << endl;
cin >> age;
cout << endl;
cin >> age;
cout << endl;
cin >> age;
cout << endl;
return age;
}
char getChoice()
{
char choice;
cout << "How do you want to see the ages displayed? \n\n Enter O for In Order, or R for In Reverse.\n\n";
cin >> choice;
return choice;
}
void displayInOrder(int numbers[], const int SIZE, char answer)
{
cout << "Here are the ages in order: \n\n";
for (int i = 0; i < SIZE; i++)
{
cout << numbers[i] << endl;
}
}
void displayInReverse(int numbers[], const int SIZE, char answer)
{
cout << "Here are the ages in reverse order: \n\n";
for (int i = SIZE - 1; i >= 0; i--)
{
cout << numbers[i] << endl;
}
}
I started working on this before the OP updated the title to their original question about "while loops & break statements". However at the time I came across this question the OP had originally removed the while loops. I was looking over the provided functions to get an idea of what the OP was trying to do and this is what I have come up with.
First: while loops are exactly what you want here, but you want a specific type of while loop, a do-while loop in this case.
Next: There is no need for break statements if you know how to structure your do-while loop correctly.
Finally: I made some modifications to the OP's existing functions by changing or removing unnecessary parameter(s), return type(s) & code duplication. I removed a function that was no longer needed. I changed the output formatting of the messages to display a clean looking program. I also removed a bad practice of having using namespace std; in the global scope.
I did this to demonstrate to the OP how a while loop can be constructed without the need of break statements and that they were originally on the right track but needed a little bit of assistance to get on their way.
Here is the source code to a working program on what I think the OP was aiming to do.
#include <iostream>
#include <cctype>
void getAge( int& age );
void displayInOrder( int numbers[], const int SIZE);
void displayInReverse( int numbers[], const int SIZE );
int main() {
const int SIZE = 5;
int numbers[SIZE] = { 0 };
char answer = '\0';
int age = 0;
char choice = '\0';
std::cout << "========================================================================\n"
<< "This program will have the user enter in "
<< SIZE
<< " Ages. \nThen ask the user in which order to display the list of ages.\n"
<< "Finally the program will ask the user if they want to continue or not.\n"
<< "========================================================================\n\n";
do {
for ( int i = 0; i < SIZE; i++ ) {
getAge( age );
numbers[i] = age;
}
std::cout << "\nPlease enter 'O' for ordered or 'R' for reversed list.\n";
std::cin >> choice;
if ( toupper( choice ) == 'O' ) {
displayInOrder( numbers, SIZE );
}
if ( toupper( choice ) == 'R' ) {
displayInReverse( numbers, SIZE );
}
std::cout << "\nDo you want to run program again (Y/N)?";
std::cin >> answer;
} while ( toupper( answer ) == 'Y' );
return 0;
}
void getAge( int& age ) {
int temp;
std::cout << "Enter an age: \n";
std::cin >> temp;
age = temp;
}
void displayInOrder( int numbers[], const int SIZE ) {
std::cout << "\nHere are the ages in order: \n";
for ( int i = 0; i < SIZE; i++ ) {
std::cout << numbers[i] << std::endl;
}
}
void displayInReverse( int numbers[], const int SIZE ) {
std::cout << "\nHere are the ages in reverse order: \n";
for ( int i = SIZE - 1; i >= 0; i-- ) {
std::cout << numbers[i] << std::endl;
}
}
#include <string>
#include <iostream>
#include <iomanip>
using namespace std;
void add(string names[], int section[], int grade[]);
void printRecords(const string names[], const int sections[], const int grades[], int size);
void insertionSort(int numbers[], int size);
void display(const int numbers[], int size);
int main(){
//command
string command;
//add
string names[20] = { "" };
int sections[20];
int grades[20];
cout << "Enter a command (add, print, drop, sort, average, quit):\n";
cin >> command;
while (command != "quit"){
if (command == "add"){
add(names,sections, grades);
}
else if (command == "print"){
printRecords(names, sections, grades, 20);
}
else if (command == "drop"){
cout << command;
}
else if (command == "sort"){
cout << command;
}
else if (command == "average"){
cout << command;
}
else if (command == "smallest"){
cout << command;
}
else{
cout << "Invalid command.\n";
}
cin >> command;
}
cout << "Quitting the program.\n";
return 0;
}
void printRecords(const string names[], const int sections[], const int grades[], int size) {
int i;
for (i = 0; i < size; i = i + 1) {
cout << "[" << i << "]:\t";
cout << setw(20) << left << names[i];
cout << setw(5) << sections[i];
cout << setw(10) << grades[i];
cout << "\n";
}
return;
}
void insertionSort(int numbers[], int size) {
int i;
int j;
int toInsert;
// outer loop i is the element we are to insert in to the sorted portion.
// [0, i-1] is the sorted range.
for (i = 1; i < size; i = i + 1) {
toInsert = numbers[i];
j = i - 1;
while (j >= 0 && numbers[j] > toInsert) {
numbers[j + 1] = numbers[j];
j = j - 1;
}
// either j >= 0 and numbers[j] <= toInsert
// or j = -1 here
// we want to store toInsert at numbers[j+1]
numbers[j + 1] = toInsert;
}
return;
}
void add(string names[], int sections[], int grades[]){
int i = 0;
while (names[i] != "" && i < 20){
i = i + 1;
}
cin >> names[i];
cin >> sections[i];
cin >> grades[i];
return;
}
I only need the user to enter a new set of information only once when the function is called.
The add function is what i care about the most. Why is it endlessly lopping?
it is suppose add one student’s record (name, section and grade) after the last record in the
current spreadsheet. Your spreadsheet should be able to hold up to 20 student records. If
there are already 20 student records, your code should prompt “Spreadsheet is full. Can
not add.”
Change cin >> command into getline(cin, command).
Here, this should fix it. What's going on is exactly what Chnossos suspects. When you cin >> the input buffer is not cleared of the newline character unless you call cin.ignore() to ignore it. However if there is no newline character you will end up waiting for it, making you enter extra input to get there.
Now, getline(cin, var) consumes the newline character, so you don't need to ignore after using this function or else you would also be waiting for more data.
I didn't look over it too terribly hard, but I coded this and it is working, thus I believe that you were just getting too many newlines and not consuming enough, thus it seemed like an infinite loop.
There are more eloquent ways to do this, but the basic gist is for strings to use getline() and for other types you can continue to use cin >> if you use cin.ignore() afterwards.
I would suggest you look this up more, also. Here is the code.
#include <string>
#include <iostream>
#include <iomanip>
using namespace std;
void add(string names[], int section[], int grade[]);
void printRecords(const string names[], const int sections[], const int grades[], int size);
void insertionSort(int numbers[], int size);
void display(const int numbers[], int size);
int main(){
//command
string command;
//add
string names[20] = { "" };
int sections[20];
int grades[20];
cout << "Enter a command (add, print, drop, sort, average, quit):\n";
getline(cin, command);
while (command != "quit"){
if (command == "add"){
add(names,sections, grades);
}
else if (command == "print"){
printRecords(names, sections, grades, 20);
}
else if (command == "drop"){
cout << command;
}
else if (command == "sort"){
cout << command;
}
else if (command == "average"){
cout << command;
}
else if (command == "smallest"){
cout << command;
}
else{
cout << "Invalid command.\n";
}
getline(cin, command);
}
cout << "Quitting the program.\n";
return 0;
}
void printRecords(const string names[], const int sections[], const int grades[], int size) {
int i;
for (i = 0; i < size; i = i + 1) {
cout << "[" << i << "]:\t";
cout << setw(20) << left << names[i];
cout << setw(5) << sections[i];
cout << setw(10) << grades[i];
cout << "\n";
}
return;
}
void insertionSort(int numbers[], int size) {
int i;
int j;
int toInsert;
// outer loop i is the element we are to insert in to the sorted portion.
// [0, i-1] is the sorted range.
for (i = 1; i < size; i = i + 1) {
toInsert = numbers[i];
j = i - 1;
while (j >= 0 && numbers[j] > toInsert) {
numbers[j + 1] = numbers[j];
j = j - 1;
}
// either j >= 0 and numbers[j] <= toInsert
// or j = -1 here
// we want to store toInsert at numbers[j+1]
numbers[j + 1] = toInsert;
}
return;
}
void add(string names[], int sections[], int grades[]){
int i = 0;
while (names[i] != "" && i < 20){
i = i + 1;
}
getline(cin, names[i]);
cin >> sections[i];
cin.ignore();
cin >> grades[i];
cin.ignore();
return;
}
The problem is that if you attempt to read into an integer, e.g. cin >> sections[i];, but you typed characters that aren't digits, then this operation fails, and cin is put into a fail state.
After that, cin remains in a fail state until you cancel that state by doing cin.clear(). This operation does not remove the problem characters from the stream either, so you usually want to combine the clear() with another read operation to read and discard the problem characters.
If you only ever type integers when your program expects integers, then your code will not "endlessly loop". Obviously you have typed in words when it was expecting integers though.
To fix this there are two things to do. First of all, always test your input functions for failure. After doing cin >> command;, also do:
if ( !cin )
{
break; // exit instead of infinitely looping
}
But it is good to detect the failure state as soon as it occurred. Inside the add function, after the last cin, you should do:
if ( !cin )
{
cout << "Invalid input entered - discarding entry\n";
names[i] = "";
cin.clear();
string junk;
getline(cin, junk);
}
(There are other ways to ignore junk but I think this one is easy to understand).
Finally, the add function uses formatted extraction (i.e. >>), so you cannot tell if the person presses Enter or not. If you want to make it so that them pressing Enter always means they've finished inputting the current entry (and invalid entry is to be discarded), then you will need to use std::getline to store the whole line in a string, and then use a stringstream to do formatted extraction from that line.
For example, the add function could be:
void add(string names[], int sections[], int grades[])
{
int i = 0;
while (names[i] != "" && i < 20){
i = i + 1;
if ( i == 20 )
return;
string line;
getline(cin, line);
istringstream iss(line);
iss >> names[i] >> sections[i] >> grades[i];
if ( !iss )
{
names[i] = "";
cerr << "Invalid entry ignored.\n";
}
}
You may need #include <sstream> for this. Note that in this version you don't need to discard the "junk", as the junk is in the stringstream which is being destroyed anyway.
As a rule of thumb, if you are mixing string and integer input, then using getline plus a stringstream will make your program more user-friendly.