Petter S
Petter S

Reputation: 51

C++ string array and bools

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++;
        }
    }
} 

Upvotes: 0

Views: 951

Answers (3)

Christophe
Christophe

Reputation: 73376

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...

Upvotes: 0

Vlad from Moscow
Vlad from Moscow

Reputation: 310980

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.

Upvotes: 0

Ra1nWarden
Ra1nWarden

Reputation: 1200

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;
}

Upvotes: 1

Related Questions