Use function in nested if statement to trigger action - c++

Below shows the main program with an if statement. If the if statement is true, then it moves onto triggering the function.
If what in the function is true, then x = true, which triggers the final action. The, x from the aux function still comes out as undeclared.
What am I doing wrong?
void aux(bool x) {
std::string text;
std::getline(std::cin, text);
if (text.find("be ") != std::string::npos ||
text.find("do ") != std::string::npos ||
text.find("can ") != std::string::npos ||
text.find("but ") != std::string::npos) {
x = true;
}
}
int main() {
std::string text;
std::getline(std::cin, text);
if (text.find("7 ") != std::string::npos) {
aux();
{
if (x);
{
std::cout<<"A function to equal a group of words"<<std::endl;
}
}
}
getchar();
return 0;
}

You may want to change your aux function to return a boolean instead of taking it as a parameter:
bool aux() {
if (/* your checks here */) {
return true;
} else {
return false;
}
}
The bool to the left of the function name, in place of void indicates that the result of calling your function will be a boolean.
Then in main you would use aux like this:
if (aux()) {
std::cout<<"A function to equal a group of words" <<std::endl;
}

Seems like you don't know about local and global variable.
You can use pass by reference to solve the problem as follows:
void aux(bool &x)
{
std::string text;
std::getline(std::cin, text);
if(text.find("be ") != std::string::npos || text.find("do ") != std::string::npos ||
text.find("can ") != std::string::npos || text.find("but ") != std::string::npos)
{
x = true;
}
else{
x = false;
}
}
int main()
{
bool x = false;
if (text.find("7 ") != std::string::npos)
{
aux(x);
//{ un-necessary brackets.
if (x);
{
std::cout<<"A function to equal a group of words" <<std::endl;
}un-necessary brackets.
//}
}
getchar();
return 0;
}
Problem you have:
You have following mistakes in your code.
1.You have defined a function like this:
void aux(bool x){
//your code here
}
But you haven't called it by passing any variable as parameter/argument. Do as following:
aux(var1);//var1 is boolean variable
2 . The change in x doesn't appear there because the x will be treated as a new variable inside the aux(var1) function. So if you use pass by reference, then the changes will be persistence to the variable (here x).

You seem to be operating on the assumption that 'x' should be available to your main() function after calling aux(). C/C++ does not work that way - there is no 'x' in the scope of your main function because you never declared anything named x.
Furthermore, it will not have the value you want unless you return x from your aux() function and assign it to something in your main function.
You should familiarize yourself with the topic of 'scope' in C/C++ as that will prevent further misunderstanding, but the basic problem you need to solve with your sample is:
You arent passing a bool to your aux() function, so it wont work (it is a parameter for aux()
You arent returning the value of x from your aux function
You arent declaring a boolean in your main function to take the value returned from aux() function

It is completely vague what is your expectations about bool x? If you want to change the x and x is outter variable then you need either pass it by the reference or return the value. Return of the value is much more logical.
bool
aux()
{
std::string text;
std::getline(std::cin, text);
if(text.find("be ") != std::string::npos ||
text.find("do ") != std::string::npos ||
text.find("can ") != std::string::npos ||
text.find("but ") != std::string::npos)
return true;
return false
}
Now it is also logical to use the result of aux() without dangling x with random value:
int main()
{
std::string text;
std::getline(std::cin, text);
if (text.find("7 ") != std::string::npos)
{
if (aux()) // We dont need the variable here since we use return value of the aux
std::cout<< "A function to equal a group of words" << std::endl;
else
std::cerr << "Bad string detected" << std::endl;
}
getchar();
return 0;
}
Now it starts to work

Related

Trying to find isogram in a string c++

I am trying to write a code that has two functions: one that determines whether the string is an isogram or not and another one to print the outcome (true or false) to the console (for the purpose of solving the task).
Some of the things are not working correctly though. And I wonder where I need to improve the code (probably all over...). I would appreciate any advice :)
#include <iostream>
#include<string>
#include<bits/stdc++.h>
#include<iomanip>
bool find_Isogram (std::string str)
{
std::sort(str.begin(), str.end()); //sorted the string for the for loop (e.g. eHllo)
int length = str.length();
for (int i = 0; i < length; i++)
{
if (str.at(i) == str.at(i+1))
{
return false;
break;
}
else
{
return true;
}
}
}
void print_result()
{
std::string str;
if (!find_Isogram (str))
{
std::cout << "false" << std::endl;
}
else
{
std::cout << "true" << std::endl;
}
}
int main()
{
find_Isogram ("gdtub");
print_result();
return 0;
};
````````````````````````````````````````````````````
There are some problems here:
1) You always check an empty string:
print_result will just check an empty string, but it's redundant anyway.
void print_result()
{
std::string str; // empty string
if (!find_Isogram (str)) // finding isogram on empty string
{
std::cout << "false" << std::endl;
}
...
}
It can be simplified with std::boolalpha that allows you to print a bool as "true" or "false" (instead of 1 or 0). main would become
int main()
{
std::cout << std::boolalpha << find_Isogram ("gdtub"); // prints true or false
};
2) Isogram check always ends after first character
Take a look at the condition in find_Isogram. It has a return-statement in the if and else, so you always return after checking the first character.
The idea to detect duplicate characters this way is correct (except for the off-by-one-error already mentioned by others). But you want to return true; only after checking all of the characters, e.g. outside the loop:
bool find_Isogram (std::string str)
{
std::sort(str.begin(), str.end()); //sorted the string for the for loop (e.g. eHllo)
int length = str.length();
for (int i = 0; i < length - 1; i++)
{
if (str.at(i) == str.at(i+1))
{
return false; // whoops duplicate char, stop here
}
}
return true; // no duplicates found, it's an isogram
}
For some further C++-magic, you could simplify it even more with standard library functions :D
bool find_Isogram (std::string str)
{
std::sort(str.begin(), str.end());
return std::unique(str.begin(), str.end()) == str.end();
}
The condition where you check the consecutive characters for equality is wrong. It will yield true for strings like ABAB. You instead need to use a map with count of each character that has appeared.
Something like:
std::map<char, int> map_of_chars;
for(int i = 0; i < length; i++) {
map_of_chars[str.at(i)] = map_of_chars[str.at(i)] + 1;
}
If any value in the map is more than 1 return false;
Another implementation would be using the return value of std::unique():
std::sort(str.begin(), str.end());
auto intial_size = str.size();
std::unique(str.begin(), str.end());
if(str.size() == initial_size) {
/is an isogram
}
else {
//is not an isogram
}

Retrieve each token from a file according to specific criteria

I'm trying to create a lexer for a functional language, one of the methods of which should allow, on each call, to return the next token of a file.
For example :
func main() {
var MyVar : integer = 3+2;
}
So I would like every time the next method is called, the next token in that sequence is returned; in that case, it would look like this :
func
main
(
)
{
var
MyVar
:
integer
=
3
+
2
;
}
Except that the result I get is not what I expected:
func
main(
)
{
var
MyVar
:
integer
=
3+
2
}
Here is my method:
token_t Lexer::next() {
token_t ret;
std::string token_tmp;
bool IsSimpleQuote = false; // check string --> "..."
bool IsDoubleQuote = false; // check char --> '...'
bool IsComment = false; // check comments --> `...`
bool IterWhile = true;
while (IterWhile) {
bool IsInStc = (IsDoubleQuote || IsSimpleQuote || IsComment);
std::ifstream file_tmp(this->CurrentFilename);
if (this->eof) break;
char chr = this->File.get();
char next = file_tmp.seekg(this->CurrentCharIndex + 1).get();
++this->CurrentCharInCurrentLineIndex;
++this->CurrentCharIndex;
{
if (!IsInStc && !IsComment && chr == '`') IsComment = true; else if (!IsInStc && IsComment && chr == '`') { IsComment = false; continue; }
if (IsComment) continue;
if (!IsInStc && chr == '"') IsDoubleQuote = true;
else if (!IsInStc && chr == '\'') IsSimpleQuote = true;
else if (IsDoubleQuote && chr == '"') IsDoubleQuote = false;
else if (IsSimpleQuote && chr == '\'') IsSimpleQuote = false;
}
if (chr == '\n') {
++this->CurrentLineIndex;
this->CurrentCharInCurrentLineIndex = -1;
}
token_tmp += chr;
if (!IsInStc && IsLangDelim(chr)) IterWhile = false;
}
if (token_tmp.size() > 1 && System::Text::EndsWith(token_tmp, ";") || System::Text::EndsWith(token_tmp, " ")) token_tmp.pop_back();
++this->NbrOfTokens;
location_t pos;
pos.char_pos = this->CurrentCharInCurrentLineIndex;
pos.filename = this->CurrentFilename;
pos.line = this->CurrentLineIndex;
SetToken_t(&ret, token_tmp, TokenList::ToToken(token_tmp), pos);
return ret;
}
Here is the function IsLangDelim :
bool IsLangDelim(char chr) {
return (chr == ' ' || chr == '\t' || TokenList::IsSymbol(CharToString(chr)));
}
TokenList is a namespace that contains the list of tokens, as well as some functions (like IsSymbol in this case).
I have already tried other versions of this method, but the result is almost always the same.
Do you have any idea how to improve this method?
The solution for your problem is using a std::regex. Understanding the syntax is, in the beginning, a little bit difficult, but after you understand it, you will always use it.
And, it is designed to find tokens.
The specific critera can be expressed in the regex string.
For your case I will use: std::regex re(R"#((\w+|\d+|[;:\(\)\{\}\+\-\*\/\%\=]))#");
This means:
Look for one or more characters (That is a word)
Look for one or more digits (That is a integer number)
Or look for all kind of meaningful operators (Like '+', '-', '{' and so on)
You can extend the regex for all the other stuff that you are searching. You can also regex a regex result.
Please see example below. That will create your shown output from your provided input.
And, your described task is only one statement in main.
#include <iostream>
#include <string>
#include <algorithm>
#include <regex>
// Our test data (raw string) .
std::string testData(
R"#(func main() {
var MyVar : integer = 3+2;
}
)#");
std::regex re(R"#((\w+|\d+|[;:\(\)\{\}\+\-\*\/\%\=]))#");
int main(void)
{
std::copy(
std::sregex_token_iterator(testData.begin(), testData.end(), re, 1),
std::sregex_token_iterator(),
std::ostream_iterator<std::string>(std::cout, "\n")
);
return 0;
}
You try to parse using single loop, which makes the code very complicated. Instead i suggest something like this:
struct token { ... };
struct lexer {
vector<token> tokens;
string source;
unsigned int pos;
bool parse_ident() {
if (!is_alpha(source[pos])) return false;
auto start = pos;
while(pos < source.size() && is_alnum(source[pos])) ++pos;
tokens.push_back({ token_type::ident, source.substr(start, pos - start) });
return true;
}
bool parse_num() { ... }
bool parse_comment() { ... }
...
bool parse_whitespace() { ... }
void parse() {
while(pos < source.size()) {
if (!parse_comment() && !parse_ident() && !parse_num() && ... && !parse_comment()) {
throw error{ "unexpected character at position " + std::to_string(pos) };
}
}
}
This is standard structure i use, when lexing my files in any scripting language i've written. Lexing is usually greedy, so you don't need to bother with regex (which is effective, but slower, unless some crazy template based implementation). Just define your parse_* functions, make sure they return false, if they didn't parsed a token and make sure they are called in correct order.
Order itself doesn't matter usually, but:
operators needs to be checked from longest to shortest
number in style .123 might be incorrectly recognized as . operator (so you need to make sure, that after . there is no digit.
numbers and identifiers are very lookalike, except that identifiers starts with non-number.

C++ void value not ignored as it ought to be (Not trying to assign a void value...)

My question is this:
Does the error appear exactly where the void value is not being ignored or can it appear at a function call that had this error occur internally?
For example, the specific problem I am having...
In my main.cpp, I have the following declarations and function call:
Dictionary * D = new Dictionary(&dictionaryFile, dictionaryName);
ifstream checkFile;
...
*D->spellCheck(&checkFile, fileName, &cout);
The function call here gives the error:
"error: void value not ignored as it ought to be"
Is this specific function call trying to use a void value or could it be within the function, which is defined as follows, in Dictionary.cpp:
void Dictionary::spellCheck(ifstream * checkFile, string fileName, std::ostream * out){
_report.setFileName(fileName);
string end = "\n";
int words = 0;
int wrong = 0;
string word;
char currChar;
while(*checkFile >> word){
currChar = checkFile->get();
while(currChar != ' ' && currChar != ',' && currChar != '.'){
word += currChar;
currChar = checkFile->get();
}
*out << word << end;
word.clear();
}
/*
_report.setWordsRead(words);
_report.setWordsWrong(wrong);
_report.printReport();
*/
}
Many thanks in advance!
*D->spellCheck(...) first calls D->spellCheck, then tries to dereference its return value. Since it returns void, you can't dereference the return value.
Remove the *.

std::string::find not working as expected in c++

I am trying to verify if a specific string is in the input string and if so do something, based on the found string; but it seems that it is always doing the first task no matter what...
if (inputString.find(str1) >= 0)
{
//do something
}
else if (inputString.find(str2) >= 0)
{
// do something else
}
else
{
std::cout << "Strange" << std::endl;
}
It is always entering the // do something block no matter if the str1 is present in inputString or not.
If I do
int str1pos = inputString.find(str1);
int str2pos = inputString.find(str2);
if (str1pos >= 0)
{
//do something
}
else if (str2pos >= 0)
{
// do something else
}
else
{
std::cout << "Strange" << std::endl;
}
it seems to work. Why is that? What am I doing wrong?
inputString.find(str1) >= 0 is always true.
This is because the return type of find is size_t which is an unsigned integer type, so it cannot be negative. Any decent compiler will give a warning for this comparison.
In your second example, when you convert the return value of find to int, if find returned npos, then the value becomes -1. That's why >= 0 works there. But if find returned a value greater than INT_MAX but not npos, the cast would turn the index to a negative value, and your logic would fail.
Therefore, you should compare to npos instead:
if (inputString.find(str1) != std::string::npos)
std::string::find returns std::string::npos if the input string is not found. To check if the string contains your input string, you must use:
if (inputString.find(str1) != std::string::npos)
{
//do something
}
else if (inputString.find(str2) != std::string::npos)
{
// do something else
}
else
{
std::cout << "Strange" << std::endl;
}
When not found, the return value is std::string::npos. It could be a positive number. You don't know.
Change your code into
if (inputString.find(str1) != std::string::npos)
{
//do something
}
else if (inputString.find(str2) != std::string::npos)
{
// do something else
}
else
{
std::cout << "Strange" << std::endl;
}

Checking if argv[i] is a valid integer, passing arguments in main

I'm trying to make sure all arguments passed to main are valid integers, and if not, I'll print an error. For example, if I have an executable named total, I would enter total 1 2 3 4.
I want to print an error if there's an invalid integer, so if I enter total 1 2 3zy it will print an error message. My code is as follows.
#include <iostream>
#include<stdlib.h>
using namespace std;
bool legal_int(char *str);
int main(int argc, char *argv[])
{
//int total = 0;
for(int i = 1; i < argc; i++)
{
if( (legal_int(argv[i]) == true) )
{
cout << "Good to go" << endl;
}
else
{
cerr << "Error: illegal integer." << endl;
return 1;
}
}
// int value = atoi(argv[i]);
//cout << value << endl;
}
bool legal_int(char *str)
{
while(str != 0) // need to
if( (isdigit(str)) )// do something here
{
return true;
}
else
{
return false;
}
}
What I need to know is how can I index through all the characters in the string and make sure they are digits with the legal_int function?
When comparing every character, the logic should be if it's not legal, return false, otherwise continue:
bool legal_int(char *str)
{
while (str != 0)
{
if (!isdigit(*str))
{
return false;
}
str++;
}
return true;
}
What about:
bool legal_int(char *str) {
while (*str)
if (!isdigit(*str++))
return false;
return true;
}
It is not the best function but it should serve the purpose. The isdigit function needs a character to look at so pass in *str. The other key point is that you need to advance the pointer inside of the loop.
bool legal_int(char *str)
{
while(str != 0) // need to
if( (isdigit(str)) )// do something here
{
return true;
}
else
{
return false;
}
}
You have three mistakes:
while (str != 0) should be while (*str != 0). You want to continue until you encounter a zero in the string, not until the string itself goes away.
if( (isdigit(str)) ) should be if( (isdigit(*str++)) ). You want to look at what str points to and see if that's a digit, and you need to point to the next digit.
return true; That should not be there. You don't want to return just because you found a single digit.