C++ string array and bools - c++

I'm currently trying to make a little recipe app. I have made a string array with 10 strings and 10 bools. For example, when I type Cinnemon I want to make the _Cinnemon true. How do I do that?
Also, is this written correctly, or could I make it better? I'm quite new to programming.
Lastly, how can I fix it so it doesn't have anything to say whether it's small letters or big?
Here's the code:
std::cout << "Welcome, type your ingredients " << std::endl;
std::string ingredients[10]{"Cinnemon", "Milk", "Eggs", "Butter", "Tomatoes", "Salt", "Backing Soda", "Suggar", "Chicken", "Honny"};
bool _cinnemon, _milk, _eggs, _butter, _tomatoes, _salt, _backingSoda, _Suggar, _chicken, _honny;
std::string ingredient;
int i = -1;
while (i = -1) {
std::cin >> ingredient;
i++;
while (i < 9)
{
if (ingredient == ingredients[i]){
std::cout << "Type another if you have any more igredients else type Exit" << std::endl;
i++;
} if (ingredient == "Exit" || "exit"){
return 0;
} else{
i++;
}
}
}

Try to map your hard-coded strings into booleans. So you can change them easily.
map<string, bool> m;
m["blah"] = false; // Initialize to false
// Later, you can change it by
m["blah"] = true;
// To look up a value, simply do
if(m.count("blah") && m["blah"]) {
// "blah" is true and do whatever you want to do here
}
As for string comparison ignoring the case, you can write your own function to do that, for example
#include <cctype> // This is where tolower() is defined
bool stringCmpIgnoreCase(string a, string b) {
if(a.length() != b.length())
return false;
for(int i = 0; i < a.length(); i++)
if(tolower(a[i]) != tolower(b[i]))
return false;
return true;
}

I understand that you are learning, so I'll avoid advanced datastructures such as maps and sets, which would be used for a real life application.
My proposed solution just uses an array of boolean. For every indegrients which string is found, I set the boolean flag at the same index. Here is how it works:
std::cout << "Welcome, type your ingredients " << std::endl;
const size_t maxind = 10; // avoid hard coded size !
std::string ingredients[maxind]{"Cinnemon", "Milk", "Eggs", "Butter", "Tomatoes", "Salt", "Backing Soda", "Suggar", "Chicken", "Honny"};
bool hasindegrient[maxind]{}; // make a table to know which one is present
std::string ingredient;
bool stopit = false; // exit requested ?
while (! stopit) {
std::cin >> ingredient;
int i;
for (i=0; i<maxind; i++)
if (ingredient == ingredients[i]){
hasindegrient[i] = true; // <================ set flag of indegrient
break;
}
if (i==maxind) { // here we didn't find it !
if (ingredient == "Exit" || ingredient == "exit")
stopit = true;
else
std::cout << "Indegrient not found !" << std::endl;
if (!stopit)
std::cout << "Type another if you have any more igredients else type Exit" << std::endl;
}
}
for (int i=0; i<10; i++) // display the indegrient list
if (hasindegrient[i])
cout << ingredients[i]<< " ";
cout << endl;
With this approach, each boolean is anonymous: each hasindegrient[i] is either true or false, but has no name. So on its own it doesn't mean anything. But in this programme, if hasindegrient[i] is true, it means that indegrients[i] is in the receipe.
If you want to add some logic where your code interprets the content of the receipe, you could add at the begin an enum that gives a logical name to each index:
enum {IDG_Cinnemon, IDG_Milk, IDG_Eggs, IDG_Butter, IDG_Tomatoes, IDG_Salt, IDG_Backing_Soda, IDG_Suggar, IDG_Chicken, IDG_Honny };
You can understand each element of this enumeration as a constant. As you see, I've followed the same order than in the table of strings. This allows then the writing of code such as:
if (hasindegrient[IDG_Butter]) {
std::cout << "Take care of your cholesterol" << std::endl;
}
Important remarks:
I think you should know some problems of your original code:
while (i = -1) will loop forever, whatever the value of i is. = is the assignement operator (i.e. -1 is copied to i and the value of i is evaluated in condition). This is the most common errors when starting with C/C++: you certainly meant while (i==-1) which is a comparison.
ingredient == "Exit" || "exit" is a valid syntax. But this condition is always true. It does in no way mean "indegrient is either Exit or exit" . For this you'd write ingredient == "Exit" || ingredient =="exit"
your loop structure will not succeed in the search. Especially if the entering of the indegrients doesn't follow the predefined list...

There are different approaches for this task. For example you could use a bool array and an enumeration with names of ingredients that would be used as indices of the array.
You could use std::bitset or std::vector<bool>
You could use an array of pairs std::pair<std::string, bool>.
Also you can use std::map.
Here is a demonstrative program
#include <iostream>
#include <map>
#include <string>
int main()
{
std::map<std::string, bool> ingredients =
{
{ "Cinnemon", false }, { "Milk", false }, { "Eggs",false },
{ "Butter", false }, { "Tomatoes", false }, { "Salt", false },
{ "Backing Soda", false }, { "Suggar", false }, { "Chicken", false },
{ "Honny", false }
};
std::cout << "Welcome, type your ingredients\n" << std::endl;
std::string ingredient;
bool selected = false;
while ( std::getline(std::cin, ingredient ) )
{
if ( ingredient == "Exit" | ingredient == "exit" ) break;
if ( selected = ( ingredients.count( ingredient ) != 0 ) )
{
ingredients[ingredient] = true;
}
else
{
std::cout << "Invalid ingredient." << std::endl;
}
std::cout << "Type another if you have any more igredients else type Exit" << std::endl;
}
if ( selected )
{
std::cout << "You selected ingredients:" << std::endl;
for ( const auto &p : ingredients )
{
if ( p.second ) std::cout << p.first << std::endl;
}
}
return 0;
}
Take into account that you have to use function std::getline instead of operator >> because some ingredient names consist from several words.
Also you should make case insensitive search.

Related

Can I compare with more than one string in an if statement?

This is gonna be laughed at because I'm probably very stupid, but can I use more than one string as a condition in an if statement?
#pragma once
#include <iostream>
#include <string>
#include "Baxter.h"
#include "Inventory.h"
#include "Room1Items.h"
int woman = 6;
int children = 5;
int inputNumberOfAnimalsToSave;
int numberOfAnimals;
int numberOfAnimalsToKill;
int numberOfAnimalToTakeHome;
std::string Yes;
std::string firstAction;
bool killRemainingAnimals;
int playerSaidYes;
int AddNumber()
{
numberOfAnimals = woman + children;
return numberOfAnimals;
}
int RemoveNumber()
{
numberOfAnimalsToKill = numberOfAnimalToTakeHome - numberOfAnimals;
return numberOfAnimalsToKill;
}
int InputNumber()
{
std::cout << " Comrade Kurchenko: Well, they are irridiated and will most likely end up poisioning \n";
std::cout << " your family, but sure, why not! How many animals Shall we Save ?\n ";
std::cin >> inputNumberOfAnimalsToSave;
numberOfAnimalToTakeHome = numberOfAnimals - inputNumberOfAnimalsToSave;
return numberOfAnimalToTakeHome;
}
int DoYouWantToKillTheRest()
{
std::cout << " Comrade Kurchenko: Fair Enough Comrade! Do you want to move on? \n\n";
std::cout << " Private Lenin: "; std::cin >> Yes;
while (Yes == "No")
{
//std::cout << " Comrade Kurchenko: So, you want the remaining " << numberOfAnimalToTakeHome << " Put The sleep do you?\n\n";
//std::cout << " Private Lenin: Im afraid so sir!\n\n";
//std::cout << " Comrade Kurchenko: Then so be it. They will be better off dead by our hands, than starving to death.\n\n\n\n";
//std::cout << " *** Loud Bangs and Then Silence....\n\n\n ***";
std::cout << " Comrade Kurchenko: What do you want to do?\n";
std::cout << " Private Lenin: "; std::cin >> firstAction; std::cout << "\n";
while (firstAction != "MoveOn")
{
if (firstAction == "Take food" || "Recover Meal" )
{
if (canTakeFood)
{
TakeFood();
std::cout << " You have taken a peice of food \n";
DoYouWantToKillTheRest();
}
if (canTakeFood == false)
{
std::cout << " There is no more food to take \n";
DoYouWantToKillTheRest();
}
}
if (firstAction == "Eatfood")
{
EatFood();
DoYouWantToKillTheRest();
}
if (firstAction == "Inventory")
{
ShowInventory();
DoYouWantToKillTheRest();
}
if (firstAction == "Ouch")
{
JabAFingerInYourEye();
std::cout << " Comrade Kurchenko : Why the hell did you stab yourself in the eye?\n\n";
std::cout << " Private Lenin : I dont know sir, its like someone was controlling my arm!\n";
DoYouWantToKillTheRest();
}
if (firstAction == "Look")
{
Look();
DoYouWantToKillTheRest();
}
if( firstAction == "Help")
{
WhatCanIDo();
DoYouWantToKillTheRest();
}
if (firstAction == "Baxter")
{
ShowBaxter();
std::cout << "Here is baxter";
DoYouWantToKillTheRest();
}
}
return 0;
}
return 0;
}
I've tried it and get no bugs when I run it. It just doesn't work.
I have tried to google it but I can't seem to find the right way to word it to get results. Messing around with a console based text adventure.
I've googled as many different ways of asking this question and can't get any results that help me.
I get no error messages. It runs fine, it just doesn't work.
"Can I compare with more than one string in an if statement?" - Sure you can (I'm assuming we are talking about std::strings here).
You are doing
if (firstAction == "Take food")
If you wanted to test against two strings you could do:
if (firstAction == "Take food" or firstAction == "Drop food")
You could change that or to || which is more conventional, but both are valid and do the same thing.
In C++ (and most other programming languages) you usually can't compare one thing (a string variable) to multiple others in one operation because of the way operator precedence is defined:
// Does not work!!
if (firstAction == "Take food" || "Recover Meal" )
// Because it will evaluate to (firstAction == "Take food") || "Recover Meal"
Rather you use logical operators to combine the result of one comparison with another comparison:
if (firstAction == "Take food" || firstAction == "Recover Meal")
{
You should read up on logical operators in C++ to learn more, for instance here: https://www.learncpp.com/cpp-tutorial/36-logical-operators/
If you want to dynamically compare to a whole list of strings, then you can do so of course as well:
std::set<std::string> validActions = {"Take food", "Recover meal"};
if (validActions.find(firstAction) != validActions.end())
{
// ... found a valid action ...
This is not how you compare c-strings in C++. That type of string is just an array of characters and operator == tells if it is the same array, not if it has the same content.
To compare strings properly use function strcmp from <cstring>.
firstAction == "Take food"; // bad
strcmp(firstAction, "Take food") == 0; // good
Better yet solution would be using class std::string which allows to use normal operators.
std::string(firstAction) == "Take food"; // good
std::string(firstAction) == std::string("Take food"); // also good
firstAction == std::string("Take food"); // also good
Or, like #JVApen has hinted, maybe even better solution would be to use std::string_view.
firstAction == std::string_view("Take food"); // good
firstAction == "Take food"sv; // the same meaning as above but written shorter
You just need to remember to insert line using std::operator""sv; before that. (using namespace std; would also do.)
If you comparing string properly (let's say using the std::string_view) then of course you can use || (or) or && (and) or any other operator to make multiple comparisons in a single if.
if (firstAction == "Take food"sv || firstAction == "Take water"sv)
{
// do stuff
}
if (firstAction == "Take food"sv && !canTakeFood)
std::cout << " There is no more food to take \n";
LoopAndDoAction();
}
(This code probably doesn't make sense but it's just an example.)
Depending on what are you trying to do, consider using enum instead of string constants. Enums are faster, more readable, take less memory and there is harder to make mistake like a type when using it. Actually, only situation I can think of when you would not want to use enum would be parsing user input.
The second if is with who you can compare strings a lot of strings if you find some condition true on these if, the entire condition will be true.
I exaplained all on code //comments
Documentation: http://www.cplusplus.com/reference/string/string/compare/
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1ok = "Im a string";
string str2ok = "Im a string";
string str3ok = "Im a string different";
//First condition with and operator (&&) you can compare with a lot && operators
if(str1ok.compare(str2ok) == 0 && str3ok.compare(str2ok) == 0){ //First condition is true, second false, this condition is false because have true and false, need have true and true for be true
cout << "1st condition" << endl;
}
//Another condition with or operator (||) one condition need be true, if not is false
if(str1ok.compare(str2ok) == 0 || str3ok.compare(str2ok) == 0){ //First condition is true, only for this this condition is true, second condition is false.
cout << "2nd condition" << endl;
}
//You can make a mixed the operators like this some condition && (anothercondition || condition)
return 0;
}
Ouptput: https://onlinegdb.com/By39WpOGS

C++ Strings Matching Returning False

I'm working on my C++ assignment. I'm having an issue with string comparison.
I'm comparing two apparently identical strings using == operating but the condition returns false. The debugger also shows that both strings (stored in different variables) are identical. I must be missing something.
Here is my code:
void classCounter() {
ifstream fread;
string linetxt;
char *records[50];
char myLine[100];
char delims[] = "|";
int btotal=0,etotal=0,total=0;
fread.open("F:\\myfile.txt");
while(!fread.eof()) {
getline(fread,linetxt,'\n');
int i = 0;
strcpy(myLine, linetxt.c_str());
records[i] = strtok( myLine, delims );
while( records[i] != NULL )
{
cout << records[i] << "|";
char *bu = "Business";
if(records[i] == bu) {
btotal++;
}
if(records[i] == "Economy") {
etotal++;
}
//printf("%d '%s'\n", i, records[i]);
records[++i] = strtok( NULL, delims );
break;
}
total++;
}
cout << "Total number of booked Business seats: " << btotal << endl;
cout << "Total number of booked Economy seats: " << etotal << endl;
cout << "Total number of booked seats: " << total << endl << endl;
}
Here is what debugger shows:
Both if conditions are returning false.
Please suggest what could be the issue.
You are comparing two pointers, and they will never be the same. Either heed the advice to use std::string (what I recommend too) or you use strcmp to compare strings.
if(records[i] == bu) {
and
if(records[i] == "Economy") {
compare two char*, not strings.
You can compare them as strings by using std::string or using the function strcmp.
Option 1: Use std::string
std::string records[50];
With that change,
if(records[i] == bu) {
and
if(records[i] == "Economy") {
should work.
Option 2: Use strcmp
if( strcmp(records[i], bu) == 0) {
and
if( strcmp(records[i], "Economy") == 0) {
Your debugger is telling you what you need to know.. You're using char* instead of String so your char* are pointers. Your program is comparing two pointers and 0x00c93bc0 != 0x002af824.
Use strcmp in the future to avoid this problem
So I'm going to assume your input file looks something like:
Business|Economy|Economy|Economy|Business
Economy|Economy|Economy|Business|Economy
...and so on. Correct? And you're trying to count up how many of each kind of ticket was sold?
If so, I'd write the code quite a bit differently. I'd probably do something like this:
std::map<std::string, int> tickets;
std::string name;
std::ifstream in("f:/myfile.txt");
int total = 0;
while (std::getline(in, name, '|')) {
++tickets[name];
++total;
}
for (auto t : tickets)
std::cout << "Total number of booked " << t.first << " seats is: " << t.second "\n";
std::cout << "Total number of booked tickets: " << total << "\n";

Keep a state when parsing text

I'm trying to make a program that looks for syntax and everytime it goes from state to state
It needs to indicate that state. I'm getting different output that I shouldn't have got.
using namespace cppfsm;
#include <vector>
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
using std::vector;
int cppfsm::updateState(int& state, char c) {
const int state1 = 1;
const int state2 = 2;
switch (state) {
case state1:
if (c == '/')
cout << "1" << endl;
// do stuff; update state
else if (c == '"')
cout << "1" << endl;
// do something else; update state
case state2:
if (c == '/')
cout << "1" << endl;
// do stuff; update state
else if (c == '"')
cout << "1" << endl;
// do something else; update state
}
return 0;
}
void testFSM(string s) {
vector<int> stlist; // list of states.
int cstate = start;
for (unsigned long i = 0; i < s.length(); i++) {
stlist.push_back(updateState(cstate,s[i]));
}
// push the last state:
stlist.push_back(cstate);
cout << s << endl;
for (unsigned long i = 0; i < stlist.size(); i++) {
cout << stlist[i];
}
cout << endl;
}
int main() {
// the finite state machine:
string input;
while(getline(cin,input)) {
cout << " ";
testFSM(input);
}
return 0;
}
the output should be looking like this.
the numbers are the states when going from 1 to another
$ echo "int x; // holds stuff" | ./fsm
int x; // holds stuff
0111010042222222222222
$ echo 'cout << "some string";' | ./fsm
cout << "some string";
01111000033333333333300
$ echo 'cout << "\"escape\" chars are fun";' | ./fsm
cout << "\"escape\" chars are fun";
011110000353333333533333333333333300
But my output comes out to be all 0000......s. How do I fix this problem?
If you're wondering why stlist is all 0's, take a look at the return statement for updateState:
return 0;
}
Compare this with your code for populating stlist:
stlist.push_back(updateState(cstate,s[i]));
As far as I can tell, all 0's is the correct behavior of this code. Obviously, this is not the expected or logical behavior, so I suggest changing updateState:
int cppfsm::updateState(int& state, char c) {
// ...
return state;
}
Now when you run the code stlist should contain each state change as intended.
It looks like you aleays call updateState with the same value, start. That value ist not handled in the switch, so the function returns zero. This means tha you just keep appending zeros to the stlist vector.
Try handling the start state in the switch, and the return value of the updateState function should be assigned to the cstate variable.
Your code never checks you start state:
switch (state) {
case state1: /* ... */
case state2: /* ... */
case start : /* ... */
}

C++ remove_if overwriting my vector

My remove_if seems to be overwriting the elements that are not filtered out with values of filtered out elements. The purpose of these code is to allow user to filter and display only teacher from a certain category. (Not deleting any element)
Here are some of the code
static string compare;
static string debug;
bool filter_Cat (Teacher &t)
{
return (t.getCat() != compare);
}
void filterCat (vector<Teacher> &t)
{
vector<Teacher>::iterator i;
vector<Teacher>::iterator newedited = remove_if(t.begin(), t.end(), filter_Cat);
for (i = t.begin(); i != newedited; ++i)
{
Teacher& te = *i;
te.getName();
cout << "\t";
te.getCategory();
cout << "\t";
te.getLocation();
}
}
void filterTutorCat(vector<Teacher> &t)
{
int choice;
cout << "No\tCategory" << endl
<< "1\tEnglish" << endl
<< "2\tMath" << endl
<< "3\tScience" << endl
<< "Choose the category you wish to filter :";
cin >> choice;
getline(cin, debug);
if(choice <= 3 && choice > 0)
{
if (choice == 1)
{
compare = "English";
filterCat(t);
}
if (choice == 2)
{
compare = "Math";
filterCat(t);
}
if (choice == 3)
{
compare = "Science";
filterCat(t);
}
}
else
{
cout << "Invalid Option" << endl;
}
}
remove_if shifts elements, for which the compare function returns false, from right to left; which in other words means, it overwrites the elements, for which compare returns true, with elements, for which compare returns false. The size of the vector doesn't change, however.
This reads,
Removes all elements satisfying specific criteria from the range [first, last). The first version removes all elements that are equal to value, the second version removes all elements for which predicate p returns true.
Removing is done by shifting the elements in the range in such a way that elements to be erased are overwritten. The elements between the old and the new ends of the range have unspecified values. Iterator to the new end of the range is returned. Relative order of the elements that remain is preserved.
So what you want to do should be expressed as:
void filterCat (vector<Teacher> &v)
{
for (vector<Teacher>::iterator it = v.begin(); it != v.end() ; ++it)
{
if (!filter_Cat(*i))
{
std::cout << i->getName() <<"\t" << i->getCategory() << std::endl;
}
}
}
It seems in your code, getName() prints the name which ideally it should not do, instead it should return name. So I would suggest you to change it to make it return name. And do the same for getCategory as well. Choose your name correctly. If it is getName(), you should get you name by returning it; if it is printName(), then it should print name.
Also, the code which you've written isn't good:
You should avoid global variables.
You should avoid if-else as much as possible. Learn better ways.
You should learn about function objects (or functor)
You should learn about const member function.
You should understand the difference between iterator and const_iterator, and their usage.
You should understand the difference between const reference, and non-const reference. And try using them appropriately.
So I would write your code as:
//this is functor, not a function
struct filter_cat
{
std::string m_cat; //use member data, avoid global variable
filter_cat(std::string const & cat) : m_cat(cat) {}
bool operator()(Teacher const & t) const //const member function
{
return (t.getCat() != m_cat); //getCat should be const member function
}
};
//pass vector by const reference
void filterCat (vector<Teacher> const & v, filter_cat filter)
{
//use const_iterator here, instead of iterator
for (vector<Teacher>::const_iterator it = v.begin(); it != v.end() ; ++it)
{
if (!filter(*i))
{
//getName and getCategory should be const member function
std::cout << i->getName() <<"\t" << i->getCategory() << std::endl;
}
}
}
void filterTutorCat(vector<Teacher> const &t)
{
int choice;
cout << "No\tCategory" << endl
<< "1\tEnglish" << endl
<< "2\tMath" << endl
<< "3\tScience" << endl
<< "Choose the category you wish to filter :";
cin >> choice;
getline(cin, debug);
//avoid if-else as much as possible, learn better ways!
std::string cats[] = {"English", "Math", "Science"};
if(choice <= 3 && choice > 0)
{
filterCat(v, filter_cat(cats[choice-1]));
}
else
{
cout << "Invalid Option" << endl;
}
}
As noted in the comments: getCat, getName and getCategory should be const member functions. In fact, if getCategory returns category, then getCat isn't even needed.
Solved my issue.
remove_if collects the values for which filter_Cat returns false at the start of the container. While it doesn't reduce the number of elements in the container it neither does make any guarantees about the values of the elements beyond the returned range. So you are loosing values when using remove_if.

I'm in need of help checking my code. Any reviewing is greatly apreciated [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 11 years ago.
This is the driver code provided by my instructor, It isn't meant to be edited by me.
PlayingCardTest.cpp:
#include <iostream>
#include "PlayingCard.h"
PlayingCard makeValidCard(int value, int suit);
int main()
{
// Create a playing card
PlayingCard card1;
// Test the default constructor and GetCardCode
std::cout << "Testing default constructor. Expect card code to be 00\n card code is :";
std::cout << card1.getCardCode() << std::endl << std::endl;
// Test the setter and getter
std::cout << "Seting card to 'AH' using SetValue and SetSuit" << std::endl;
card1.setCard('A', 'H');
std::cout << "GetValue returns :" << card1.getValue() << std::endl;
std::cout << "GetSuit returns :" << card1.getSuit() << std::endl << std::endl;
// Test overloaded constructor
PlayingCard tenOfSpades('T', 'S');
std::cout << "Testing overloaded constructor. Expect card code to be TS\n card code is :";
std::cout << tenOfSpades.getCardCode() << std::endl << std::endl;
// Test IsValid with valid cards
std::cout << "Testing valid card codes.\n"
<< "Expect isValid to return true for all (except perhaps Jokers.)"
<< std::endl;
// Create and test valid cards
int validCards = 0; // cards that return true for IsValid
int invalidCards = 0; // cards that return false for IsValid
// Create and test four suits plus the jokers
for(int suit = 1; suit <= 5; suit++)
{
// Create and test ace, 2 - 9, Jack, Queen, and King
for(int value = 1; value <= 13; value++)
{
PlayingCard aCard = makeValidCard(value, suit);
std::cout << "Card Code: " << aCard.getCardCode() << " IsValid :";
if (aCard.isValid())
{
validCards++;
std::cout << "true" << std::endl;
}
else
{
invalidCards++;
std::cout << "false" << std::endl;
}
// suit 5 is just for creating the two Jokers
if (suit == 5 && value >= 2)
break;
}
}
std::cout << "IsValid returned false for " << invalidCards << " card codes" << std::endl;
std::cout << "IsValid returned true for " << validCards << " card codes" << std::endl;
std::cout << std::endl;
// Test IsValid with invalid cards
// Create and test invalid cards
std::cout << "Testing invalid card codes; isValid should return false for all." << std::endl;
validCards = 0;
invalidCards = 0;
// Loop through all possible ASCII character codes for card codes
for(int suit = 0; suit <= 255; suit++)
for(int value = 0; value <= 255; value++)
{
// Only check card codes that are not valid
PlayingCard aCard = makeValidCard(value, suit);
if (aCard.getCardCode() == "00")
{
if (aCard.isValid())
{
std::cout << "value :" << value << " suit :" <<suit << " IsValid :";
std::cout << "true" << std::endl;
validCards++;
}
else
{
invalidCards++;
}
}
}
std::cout << "IsValid returned false for " << invalidCards << " card codes" << std::endl;
std::cout << "IsValid returned true for " << validCards << " card codes" << std::endl;
return 0;
}
/******************************************************/
/* Test Functions */
/******************************************************/
PlayingCard makeValidCard(int iValue, int iSuit)
{
char value = '0';
char suit = '0';
switch (iValue)
{
case 1:
value = 'A';
break;
case 10:
value = 'T';
break;
case 11:
value = 'J';
break;
case 12:
value = 'Q';
break;
case 13:
value = 'K';
break;
default:
if ((iValue >= 2) && (iValue <= 9))
value = '0' + iValue;
break;
}
switch (iSuit)
{
case 1:
suit = 'D';
break;
case 2:
suit = 'S';
break;
case 3:
suit = 'C';
break;
case 4:
suit = 'H';
break;
// Special case for the Joker
case 5:
if(iValue == 1)
{
value = 'Z';
suit = 'B';
}
else if(iValue == 2)
{
value = 'Z';
suit = 'R';
}
else
{
value = '0';
suit = '0';
}
break;
}
PlayingCard testCard(value, suit);
return testCard;
}
This is my header file, PlayingCard.h:
#ifndef PLAYINGCARD_H_INCLUDED
#define PLAYINGCARD_H_INCLUDED
class PlayingCard
{
private:
char suit, value;
public:
PlayingCard(){suit = '0'; value = '0';}
PlayingCard(char myValue, char mySuit);
char getValue() {return value;}
char getSuit() {return suit;}
std::string getCardCode();
bool setCard(char myValue, char mySuit);
bool isValid();
#endif // PLAYINGCARD_H_INCLUDED
And this is my class implementation file, PlayingCard.cpp:
#include "PlayingCard.h"
PlayingCard::PlayingCard (char myValue, char mySuit)
{
char aValue[13] ('2','3','4','5','6','7','8','9','T','J','Q','K','A'))
char aSuit[4] {'D','H','C','S']
for(count = 0; count <= 12; count++)
{
if (myValue = aValue[count])
{
for (count2 = 0; count2 <= 3; count2++)
{
if (mySuit = aSuit[count2++])
{
suit = mySuit;
value = myValue;
}
}
}
}
}
bool PlayingCard::setCard(char myValue, char mySuit)
{
char aValue[13] ('2','3','4','5','6','7','8','9','T','J','Q','K','A'))
char aSuit[4] {'D','H','C','S']
for(count = 0; count <= 12; count++)
{
if (myValue = aValue[count])
{
for (count2 = 0; count2 <= 3; count2++)
{
if (mySuit = aSuit[count2++])
{
suit = mySuit;
value = myValue;
}
else
{
return false;
}
}
}
}
}
string PlayingCard::getCardCode()
{
return suit + value;
}
bool PlayingCard::isValid()
{
char aValue[13] ('2','3','4','5','6','7','8','9','T','J','Q','K','A'))
char aSuit[4] {'D','H','C','S']
for(count = 0; count <= 12; count++)
{
if (myValue = aValue[count])
{
for (count2 = 0; count2 <= 3; count2++)
{
if (mySuit = aSuit[count2++])
{
return true;
}
else
{
return false;
}
}
}
}
}
And this is the compiler errors I'm getting. I'm not sure what to do, it looks like they are in the file I shouldn't edit. I would really appreciate help you can give.
PlayingCardTest.cpp|103|error: 'PlayingCard PlayingCard::makeValidCard(int, int)' cannot be overloaded|
PlayingCardTest.cpp|5|error: with 'PlayingCard PlayingCard::makeValidCard(int, int)'|
PlayingCardTest.cpp|169|error: expected '}' at end of input|
PlayingCardTest.cpp|169|error: expected unqualified-id at end of input|
||=== Build finished: 4 errors, 0 warnings ===|
You are missing }; at the end of your header file.
First round of comments:
Style nit: order sections "public", "protected", then "private". Private section should not go before public. This is not technically required, but is fairly standard practice.
Style nit: declare each variable using a separate statement, each on its own line. Using commas is a good way to get in trouble (e.g. when declaring pointer types) and is poor style.
Use an initialization list in the constructor rather than using the assignment operator.
You should include "<string>" in your header to use std::string.
Second round of comments:
You are initializing your arrays weirdly; you should use {} as the brackets.
You do not need to specify the size of the arrays in the initialization.
Style nit: do not use magic constants like "12" in your code. Instead, assign them to a variable such as value_length or value_count, and use the named variable.
Did you mean to do an equals comparison ("==") or an assignment ("=") in your if-statement? If you meant to do an assignment, you should probably move it outside of the if.
Third round of comments:
You unnecessarily duplicate code between your non-default constructor and your setCard function. You should be able to share code between those two functions. Since setCard is not a virtual function, you should be able to simply call it from your constructor.
Your setCard logic seems fairly complicated. Most "set" functions are much more trivial than that. You should consider adding documentation explaining the logic of what it is trying to do.
The "getValue()", "getCardCode()", "getSuit()", and "isValid()" functions should be declared "const".
Fourth round of comments:
Since your professor does "PlayingCard card = makeValidCard(....)", it is clear that he wants your card class to support assignment. Since your "setCard()" function and your non-default constructor do something other than simply set the attributes, it would make sense to provide a "PlayingCard& operator=(const PlayingCard&);" assignment operator as well as a "PlayingCard::PlayingCard(const PlayingCard&)" copy constructor. If you do not provide these, it is good practice to add a comment to the effect that copying using the default assignment / copy has been intentionally allowed.