The problem with the code below is, no matter what what the input is in the console, all the functions run as if they were true. As an example, I could input "vvvvvvvvvvvvvvvv" and both "hello" and "good thank you" would output. Its as if the parameters of the functions don't matter.
#include <windows.h>
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
void main()
{
void confirmChk(bool &confirm);
bool confirm = false;
void greetingChk(bool &greeting);
bool greeting = false;
void questionChk(bool &question);
bool question = false;
void youChk(bool &you);
bool you = false;
std::string text;
std::getline(std::cin, text);
for (int read = 0; read < text.length(); read++)
{
greetingChk(greeting);
if (greeting = true);
{
youChk(you);
if (you = true);
{
std::cout<<"hello" <<std::endl;
}
}
questionChk(question);
if (question = true);
{
youChk(you);
if (you = true);
{
std::cout<<"good thank you" <<std::endl;
}
}
std::chrono::milliseconds dura(2000);
std::this_thread::sleep_for(dura);
system("cls");
}
}
//////////////////Functions//////////////////
void greetingChk(bool &greeting)
{
std::string text;
std::getline(std::cin, text);
if(text.find("hi ") != std::string::npos ||
text.find("hello ") != std::string::npos ||
text.find("hey ") != std::string::npos ||
text.find("yo ") != std::string::npos ||
text.find("sup ") != std::string::npos ||
text.find("howdy ") != std::string::npos ||
text.find("wazzup ") != std::string::npos ||
text.find("hiya ") != std::string::npos)
{
greeting = true;
}
else
{
greeting = false;
}
}
void youChk(bool &you)
{
std::string text;
std::getline(std::cin, text);
if(text.find("ya ") != std::string::npos ||
text.find("you ") != std::string::npos ||
text.find("yah ") != std::string::npos ||
text.find("yall ") != std::string::npos ||
text.find("you're ") != std::string::npos)
{
you = true;
}
else
{
you = false;
}
}
void questionChk(bool &question)
{
std::string text;
std::getline(std::cin, text);
if(text.find("are") != std::string::npos ||
text.find("am") != std::string::npos ||
text.find("can") != std::string::npos ||
text.find("could") != std::string::npos ||
text.find("do") != std::string::npos ||
text.find("does") != std::string::npos ||
text.find("did") != std::string::npos ||
text.find("has") != std::string::npos ||
text.find("had") != std::string::npos ||
text.find("have") != std::string::npos ||
text.find("is") != std::string::npos ||
text.find("may") != std::string::npos ||
text.find("might") != std::string::npos ||
text.find("shall") != std::string::npos ||
text.find("should") != std::string::npos ||
text.find("was") != std::string::npos ||
text.find("would") != std::string::npos ||
text.find("were") != std::string::npos)
{
question = true;
}
else
{
question = false;
}
}
void confirmChk(bool &confirm)
{
std::string text;
std::getline(std::cin, text);
if(text.find("ok") != std::string::npos ||
text.find("yup") != std::string::npos ||
text.find("yes") != std::string::npos ||
text.find("affirm") != std::string::npos ||
text.find("affirmative") != std::string::npos ||
text.find("confirm") != std::string::npos ||
text.find("confirmed") != std::string::npos ||
text.find("confirming") != std::string::npos ||
text.find("endorse") != std::string::npos ||
text.find("endorsed") != std::string::npos ||
text.find("approve") != std::string::npos ||
text.find("approved") != std::string::npos ||
text.find("approving") != std::string::npos ||
text.find("of course") != std::string::npos ||
text.find("got it") != std::string::npos ||
text.find("will do") != std::string::npos ||
text.find("alright") != std::string::npos ||
text.find("fine") != std::string::npos ||
text.find("varify") != std::string::npos ||
text.find("ratify") != std::string::npos ||
text.find("validate") != std::string::npos ||
text.find("understood") != std::string::npos ||
text.find("justify") != std::string::npos)
{
confirm = true;
}
else
{
confirm = false;
}
}
Your if statements have more entries then a teenage girls phone. :-)
You should invest in some structures, containers and loops.
For example:
const static std::string question_words[] =
{"am", "are", "can", "did", "could", "do", "does"};
const static unsigned int word_quantity =
sizeof(question_words) / sizeof(question_words[0]);
//...
bool is_question = false;
for (unsigned int i = 0; i < word_quantity; ++i)
{
if (text == question_word[i])
{
is_question = true;
break;
}
}
You can put this logic into a function, and pass it the word array and the word. That way, you can call the function for the different word containers and not write extra code. Your code would like like:
bool is_question = false;
is_question = Is_Word_In_Array(question_words, word_quantity, text);
if (is_question)
{
cout << "sentence is a question\n";
}
if (Is_Word_In_Array(greeting_words, greeting_word_quantity, text))
{
cout << "sentence has a greeting.\n";
}
If you sort the arrays, you can use existing search functions like std::binary_search to find your word.
I hardly know where to begin. Your main loop executes as many times as there are characters in your input string.
All of your if statements are true, because you set them that way.
Saying
if (greeting = true);
first sets greeting to true, and then does nothing (because of the semicolon right after the conditional clause).
The following statements within braces will be executed because they are not part of the if. Again, because of the semicolon after the conditional clause.
Use something more like
if (greeting)
{
// conditional code here
}
I think you really meant if (greeting == true) which is the same as if (greeting).
Here's one of your problems: You're using the assignment operator = instead of the equality operator ==. So, when you use:
if (greeting = true)
...you're saying "set greeting to true. if the results of this operation return true, then ..." What you want to use is this:
if (greeting == true)
This says "compare greeting to true. if the results of this operation return true (i.e. if they are equal), then..." However, you can actually make this a little more concise with this:
if (greeting)
Related
I am new to programming and I need to search any string to see if it includes only the letters a,b,c,d,e or f. The minute the program finds a letter that is not one of those the program should return false. Here is my function
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if ((word[index] == 'a') || (word[index] == 'b') || (word[index] == 'c')||
(word[index] == 'd')|| (word[index] == 'e')|| (word[index] == 'f')) {
return true;
}
else {
return false;
}
index++;
}
}
Thank you very much for nay help! :)
The moment the return statement is encountered, the function is exited. This means that the moment any of the characters 'a', 'b', 'c', 'd', 'e', 'f' is encountered while iterating, due to the return statement the function will be exited immediately.
You can use std::string::find_first_not_of as shown below:
std::string input = "somearbitrarystring";
std::string validChars = "abcdef";
std::size_t found = input.find_first_not_of(validChars);
if(found != std::string::npos)
std::cout << "Found nonfavorite character " <<input[found]<<" at position "<<found<< std::endl;
else
{
std::cout<<"Only favorite characters found"<<std::endl;
}
If you unroll the loop by hand, you will spot the problem immediately:
if ((word[0] == 'a') || (word[0] == 'b') || (word[0] == 'c')||
(word[0] == 'd')|| (word[0] == 'e')|| (word[0] == 'f')) {
return true;
}
else {
return false;
}
if ((word[1] == 'a') || (word[1] == 'b') || (word[1] == 'c')||
(word[1] == 'd')|| (word[1] == 'e')|| (word[1] == 'f')) {
return true;
}
else {
return false;
}
//...
That is, the return value depends only on the first element.
"The minute the program finds a letter that is not one of those the program should return false" means
if ((word[0] != 'a') || (word[0] != 'b') || (word[0] != 'c')||
(word[0] != 'd')|| (word[0] != 'e')|| (word[0] != 'f')) {
return false;
}
if ((word[1] != 'a') || (word[1] != 'b') || (word[1] != 'c')||
(word[1] != 'd')|| (word[1] != 'e')|| (word[1] != 'f')) {
return false;
}
// ...
// After checking all the characters, you know what all them were in
// your desired set, so you can return unconditionally.
return true;
or, with a loop:
while (index < length) {
if ((word[index] != 'a') || (word[index] != 'b') || (word[index] != 'c')||
(word[index] != 'd')|| (word[index] != 'e')|| (word[index] != 'f')) {
return false;
}
index++;
}
return true;
bool is_favorite(string word){
return ( word.find_first_not_of( "abcdef" ) == std::string::npos );
}
It returns true if, and only if, there are only the characters 'a' through 'f' in the string. Any other character ends the search immediately.
And if you exchange string word with const string & word, your function will not have to create a copy of each word you pass to it, but work on a read-only reference to it, improving efficiency.
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if (word[index] > 'f' || word[index] < 'a')
return false;
index++;
}
return true;
}
The return true is logically in the wrong place in your code.
Your version returns true as soon as it finds one letter that is a through f. It's premature to conclude that the whole string is valid at that point, because there may yet be an invalid character later in the string.
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if ((word[index] == 'a') || (word[index] == 'b') || (word[index] == 'c')||
(word[index] == 'd')|| (word[index] == 'e')|| (word[index] == 'f')) {
return true; // This is premature.
}
else {
return false;
}
index++;
}
}
Minimal change that illustrates where the return true should be: after the loop. The return true is reached only if and only if we did not detect any invalid characters in the loop.
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if ((word[index] == 'a') || (word[index] == 'b') || (word[index] == 'c')||
(word[index] == 'd')|| (word[index] == 'e')|| (word[index] == 'f')) {
// Do nothing here
}
else {
return false;
}
index++;
}
return true;
}
Obviously now that the affirmative block of the if is empty, you could refactor a little and only check for the negative condition. The logic of it should read closely to the way you described the problem in words:
"The minute the program finds a letter that is not one of those the program should return false."
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if (!is_letter_a_through_f((word[index])
return false;
index++;
}
return true;
}
I replaced your large logical check against many characters with a function in the above code to make it more readable. I trust you do that without difficulty. My own preference is to keep statements short so that they are readable, and so that when you read the code, you can hold in your short-term memory the logic of what you are saying about control flow without being overloaded by the mechanics of your letter comparison.
I'm very inexperienced with C++. I have a program that runs well. Part of the code relies on identifying some text in the name of a pop up window.
This is the partial part of code (which works fine)
std::string firstNeedle("DX");
std::size_t firstSearch = upperCaseWindowName.find(firstNeedle);
std::string secondNeedle("BENJA");
std::size_t secondSearch = upperCaseWindowName.find(secondNeedle);
std::string thirdNeedle("BWB");
std::size_t thirdSearch = upperCaseWindowName.find(thirdNeedle);
std::string fourthNeedle("WDX");
std::size_t fourthSearch = upperCaseWindowName.find(fourthNeedle);
if ((firstSearch != std::string::npos) || (secondSearch != std::string::npos) || (thirdSearch != std::string::npos) || (fourthSearch != std::string::npos) ) {
I need to add quite a few more search terms and this method just isn't really sustainable.
I wondered if it's possible to do something like this (pseudo code):
string textToLookFor[] = { "DX", "BENJA", "BWB", "WDX", "FOO", "BAR" };
std::size_t searchingWindow = upperCaseWindowName.find(textToLookFor);
if ( (textToLookFor != std::string::npos) ){
Then I would simply add further terms to the array?
Firstly, it becomes slightly more sustainable if you rewrite it like this:
if (upperCaseWindowName.find("DX" ) != std::string::npos ||
upperCaseWindowName.find("BENJA") != std::string::npos ||
... )
Or you can use a for loop:
std::string patterns[] = {"DX", "BENJA", ...};
bool found = false;
for (const std::string &p : patterns)
{
if (upperCaseWindowName.find(p) != std::string::npos)
{
found = true;
break;
}
}
if (found) {...}
Or std::any_of:
std::string patterns[] = {"DX", "BENJA", ...};
if (std::any_of(std::begin(patterns), std::end(patterns),
[&](const std::string &p){return upperCaseWindowName.find(p) != std::string::npos;}))
{...}
Here is a problem I have , I have a vector of filenames and I want to check if they end by .jpg or by .png so I made some code with iterators and the STL, this i also for creating a std::map with those names as keys and with value a texture, so here is my code, that does a Segmentation Fault error at the line 11:
#include "TextureManager.h"
std::map<std::string,sf::Texture> createTextureArray(){
std::map<std::string,sf::Texture> textureArray;
std::vector<std::string>::iterator strIt;
std::string fName;
for(strIt = textureFileList().begin(); strIt != textureFileList().end(); strIt++){
sf::Texture texture;
fName = *strIt;
if(fName[fName.size()] == 'g' && fName[fName.size()-1] == 'p' && fName[fName.size()-2] == 'j' && fName[fName.size()-3] == '.'){
texture.loadFromFile(fName);
textureArray[fName] = texture;
}
else if(fName[fName.size()] == 'g' && fName[fName.size()-1] == 'n' && fName[fName.size()-2] == 'p' && fName[fName.size()-3] == '.'){
texture.loadFromFile(fName);
textureArray[fName] = texture;
}
}
return textureArray;
}
I think this is the only code needed to try to understand the problem , but if anyone wants more of this code here is the Github repo
This is not shown in your question, but textureFileList returns by value, which means that you get a copy of the std::vector<std::string> it returns. You're calling this function twice, once for begin() and then once for end(), which means you're calling those functions on different copies of the vector. Obviously the beginning of one copy has no relation to the end of another copy. Not only this, but those copies are being destroyed immediately afterwards, because they are temporaries. Instead, you should store a single copy and call begin and end on that:
std::vector<std::string> fileList = textureFileList();
for(strIt = fileList.begin(); strIt != fileList.end(); strIt++){
And fName[fName.size()] is always '\0'.
You should use
if(fName[fName.size()-1] == 'g' && fName[fName.size()-2] == 'p' && fName[fName.size()-3] == 'j' && fName[fName.size()-4] == '.'){
and
else if(fName[fName.size()-1] == 'g' && fName[fName.size()-2] == 'n' && fName[fName.size()-3] == 'p' && fName[fName.size()-4] == '.'){
I suppose that function textureFileList() returns an object of type std::vector<std::string> by reference.
The segmentation fault can occur due to accessing non-existent character of a string.
if(fName[fName.size()] == 'g' && fName[fName.size()-1] == 'p' && fName[fName.size()-2] == 'j' && fName[fName.size()-3] == '.'){
There is no such character of the string with index fName.size(). The valid range of indexes is 0, size() -1 provided that size() is not equal to zero.
You should use another approach. You have to find the period using member function rfind() and then compare the substring with a given extension.
Here is an example
#include <iostream>
#include <string>
int main()
{
std::string s( "SomeFile.jpg" );
std::string::size_type n = s.rfind( '.' );
if ( n != std::string::npos && s.substr( n ) == ".jpg" )
{
std::cout << "It is a JPEG file" << std::endl;
}
return 0;
}
The output is
It is a JPEG file
Your for loop could be written the following way
for ( const std::string &fName : textureFileList() )
{
const char *ext[] = { "jpg", "png" };
std::string::size_type n = s.rfind( '.' );
if ( n != std::string::npos &&
( fName.substr( n + 1 ) == ext[0] || fName.substr( n + 1 ) == ext[1] ) )
{
sf::Texture texture;
texture.loadFromFile( fName );
textureArray[fName] = texture;
}
}
If you need to erase the extension then you can write simply
fName.erase( n );
In this case fName has to be defined as a non-const reference in the for statement.
I'm doing some string manipulation, and am looping through a string with a string iterator, and under certain conditions insert a character into the string. Here is the code:
string * const Expression::process(char * const s)
{
if(s == NULL)
{
printf("(from Expression::process())\n > NULL data");
return NULL;
}
string *rtrn = new string(s);
string garbage;
//EDIT
rtrn->erase(remove(rtrn->begin(), rtrn->end(), ' '), rtrn->end());
for(string::iterator j = rtrn->begin(); (j+2) != rtrn->end(); j++)
{
if(Operator::isValid(&*j, garbage) != Operator::SYM && *(j+1) == '-' && (Operator::isValid(&(*(j+2)), garbage) != Operator::INVALID))
rtrn->replace(j+1, j+2, "+-");
}
rtrn->insert(rtrn->begin(), '(');
rtrn->append(")");
for(string::iterator k = rtrn->begin(); k+1 != rtrn->end(); k++)
{
if(*k == '-' && !Operator::isValidNum(*(k+1)))
rtrn->replace(k, k+1, "-1*");
if((Operator::isValid(&*(k+1), garbage) != Operator::INVALID && (Operator::isValid(&*(k+1), garbage) != Operator::SYM || *(k+1)=='(')) &&
(Operator::isValid(&*k, garbage) == Operator::VAR || Operator::isValidNum(*k) || *k==')') &&
!(Operator::isValid(&*k, garbage) == Operator::NUM && Operator::isValid(&*(k+1), garbage) == Operator::NUM))
{
if(Operator::isValid(&*k, garbage) == Operator::SYM)
{
if(opSymb::valid[garbage]->getArguments())
rtrn->insert(k+1, '*');
}
else
{
rtrn->insert(k+1, '*');
}
}
}
return rtrn;
}
When s is equal to "20x(5x+3)-6x(5x^2+11/2)", I get a runtime error at rtrn->insert(k+1, '*'); under the else statement when it gets to "5x^2" in the string. Basically, when it makes the 6th insertion, it crashes on me and complains about the iterator + operator being out of range. Although, when I'm debugging, it does pass the correct offset. And it does successfully insert the char into the string, but after the function executes, the iterator is pointing to corrupt data.
for(string::iterator i = rtrn->begin(); i != rtrn->end(); i++)
{
if(*i == ' ')
rtrn->erase(i);
}
There are errors in this and all code snippets like this: for loop can`t be used for deleting element from a container, becase erase() - invalidates all iterators related to the container,
I offer you to use while loop instead, here is a short example from another question I answered:
string::iterator it = input.begin();
while (it != input.end())
{
while( it != input.end() && isdigit(*it))
{
it = input.erase(it);
}
if (it != input.end())
++it;
}
So after research and help from you guys, it seems I have to refine my code so that any string functions such as erase, insert, or replace writes over the iterator passed to the function. So I need to change my code to something like this
for(string::iterator k = rtrn->begin(), m=k+1; m != rtrn->end(); k=m, m=k+1)
{
if(*k == '-' && !Operator::isValidNum(*m))
rtrn->replace(k, m, "-1*");
if((Operator::isValid(&*m, garbage) != Operator::INVALID && (Operator::isValid(&*m, garbage) != Operator::SYM || *m=='(')) &&
(Operator::isValid(&*k, garbage) == Operator::VAR || Operator::isValidNum(*k) || *k==')') &&
!(Operator::isValid(&*k, garbage) == Operator::NUM && Operator::isValid(&*m, garbage) == Operator::NUM))
{
if(Operator::isValid(&*k, garbage) == Operator::SYM)
{
if(opSymb::valid[garbage]->getArguments())
rtrn->insert(m, '*');
}
else
{
m=rtrn->insert(m, '*');
}
}
}
I'm working on a project in c++ (which I just started learning) and can't understand why this function is not working. I'm attempting to write a "Person" class with a variable first_name, and use a function set_first_name to set the name. Set_first_name needs to call a function(the one below) to check if the name has any numbers in it. The function always returns false, and I'm wondering why? Also, is this the best way to check for numbers, or is there a better way?
bool Person::contains_number(std::string c){ // checks if a string contains a number
if (c.find('0') == std::string::npos || c.find('1') == std::string::npos || c.find('2') == std::string::npos || c.find('3') == std::string::npos
|| c.find('4') == std::string::npos || c.find('5') == std::string::npos || c.find('6') == std::string::npos || c.find('7') == std::string::npos
|| c.find('8') == std::string::npos || c.find('9') == std::string::npos){// checks if it contains number
return false;
}
return true;
}
Change all your || to &&.
Better yet:
return std::find_if(s.begin(), s.end(), ::isdigit) != s.end();
Or, if you have it:
return std::any_of(s.begin(), s.end(), ::isdigit);
C++11:
#include <algorithm>
#include <cctype>
#include <string>
#include <iostream>
bool has_any_digits(const std::string& s)
{
return std::any_of(s.begin(), s.end(), ::isdigit);
}
int main()
{
std::string query("H311o, W0r1d!");
std::cout << query << ": has digits: "
<< std::boolalpha
<< has_any_digits(query)
<< std::endl;
return 1;
}
Output:
H311o, W0r1d!: has digits: true
It always returns false because your logic is backwards. You are using the || operator with == npos checks. If any one particular digit is missing from the string, == npos evaluates to true and || is satisfied, so you return false. You need to using != npos checks and then return true if any check evaluates to true:
bool Person::contains_number(const std::string &c)
{
if (c.find('0') != std::string::npos ||
c.find('1') != std::string::npos ||
c.find('2') != std::string::npos ||
c.find('3') != std::string::npos ||
c.find('4') != std::string::npos ||
c.find('5') != std::string::npos ||
c.find('6') != std::string::npos ||
c.find('7') != std::string::npos ||
c.find('8') != std::string::npos ||
c.find('9') != std::string::npos)
{
return true;
}
return false;
}
Or:
bool Person::contains_number(const std::string &c)
{
return (
c.find('0') != std::string::npos ||
c.find('1') != std::string::npos ||
c.find('2') != std::string::npos ||
c.find('3') != std::string::npos ||
c.find('4') != std::string::npos ||
c.find('5') != std::string::npos ||
c.find('6') != std::string::npos ||
c.find('7') != std::string::npos ||
c.find('8') != std::string::npos ||
c.find('9') != std::string::npos
);
}
A simplier solution is to use find_first_of() instead of find():
bool Person::contains_number(const std::string &c)
{
return (c.find_first_of("0123456789") != std::string::npos);
}
How to test if a string contains any digits in C++
This should do it!
if (std::string::npos != s.find_first_of("0123456789"))
{
std::cout << "digit(s)found!" << std::endl;
}
You are using || (or operator) to check several conditions in an if statement.
The or operator returns true (satisfies the condition) if one of the expression is true.
The or operator evaluates first the expression on its left: if that is true then it doesn't evaluate the expression on its right and returns true.
If the expression on the left is false then the expression on the right is evaluated and the result of it is returned as result of || operator
This is what happen in your function:
does c contains '0' ? if no (because std::string::npos in find() means not found) then return false
does c contains '1' ? if no then return false
...
So, replace the or operators with && (and operator).