Trying to check entered text versus my own custom answers - c++

here is what I attempted to throw together, unfortunately it's not doing what I want it to. What I want it to be doing is checking the entered text vs a few words that I consider correct. So, for example, if I want the only correct answers to be "thanks" or "please", how would I make the program check if the word the user entered is either "thanks" or "please"?
I have a feeling I can't just write B == 'funs etc.
help me out please:
#include <iostream>
using namespace std;
int main ()
{
string B;
for (;;)
{cout << "enter text here" << '\n' ;
cin >> B ;
if (B == 'fUNS'|| B == 'funs' || B == 'funzies')
{
cout << "correct!!!!!!" << endl;
break;
}
else
{
cout << "sorry, please try again" << endl;
continue;
}
}
return 0;
}

Unlike some languages using ' or " to enclose a sequence of characters produces very different results.
A single quote defines a single character literal e.g:
char a = 'A';
You can use multiple characters to define the value of an integer (although this is non-standard):
int a = 'ABCD';
A double quote defines a string literal which is a sequence of characters in an array:
const char str[5] = "ABCD";
Note the literal has a hidden null character at the end which is why it has 5 elements rather than 4. String literals are comparable and assignable with std::string:
std::string test( "ABCD" );
std::cout << test == "ABCD";
test = "EFGH";
std::cout << test == "ABCD";

I have a feeling I can't just write B == 'funs etc.
Yes, you can, since B is a std::string, which has an operator== defined. You just need to use " (which is used to define string literals) instead of ' (which is used to define character literals), eg:
if (B == "fUNS" || B == "funs" || B == "funzies")

Related

Why does toupper function return an ASCII instead of a char? [duplicate]

int main()
{
char hmm[1000];
cin.getline(hmm, 1000);
cout << hmm << endl; //this was to test if I could assign my input to the array properly
for (int sayac = 0; hmm[sayac] != '#'; sayac++) {
if (!isdigit(hmm[sayac])) {
if (islower(hmm[sayac]))
cout << toupper(hmm[sayac]);
else if (isupper(hmm[sayac]))
cout << tolower(hmm[sayac]);
else
cout << hmm[sayac];
}
}
"Write a program that reads keyboard input to the # symbol and that echoes the input
except for digits, converting each uppercase character to lowercase, and vice versa.
(Don’t forget the cctype family.) "
I'm doing this exercise from the primer book. But when I run it, it returns the ascii order of the char, not the uppercase/lowercase version of the character. Couldn't figure out the problem. Can someone tell my why please?
(I may have other problems about the exercise, please don't correct them if I have. I want to fix it on my own (except the problem I explained), but I can't check the other ones as I have this problem.
When writing
std::cout << toupper('a');
the following happen:
int toupper(int ch) is called, and returns an integer whose value is 'A' (0x41).
std::basic_ostream::operator<<(std::cout, 0x41) is called, that is the int (2) overload since an int was provided.
Overall, it prints "65".
As a solution, you can cast back your upper case to a char:
std::cout << static_cast<char>(toupper('a'));
It's a question of representation. There is no difference between a character and that character's numeric value. It's all in how you choose to display it. For example, the character 'a' is just a constant with a value equal to the character's numeric value.
The problem you are having is that std::toupper and std::tolower return an int rather than a char. One reason for that is that they handle EOF values, which are not necessarily representable by char. As a consequence, std::cout see you are trying to print an int and not a char. The standard behavior for streaming an int is to print the number. The solution is then to cast your result to char to force the value to be interpreted as a character. You can use something like std::cout << static_cast<char>(std::toupper(hmm[sayac]));.
Try the following :
#include <cctype>
#include <iostream>
int main()
{
char hmm[1000];
std::cin.getline(hmm, 1000);
std::cout << hmm << std::endl; //this was to test if I could assign my input to the array properly
for (int sayac = 0; hmm[sayac] != '#'; sayac++) {
if (!std::isdigit(hmm[sayac])) {
if (std::islower(hmm[sayac]))
std::cout << static_cast<char>(std::toupper(hmm[sayac]));
else if (isupper(hmm[sayac]))
std::cout << static_cast<char>(std::tolower(hmm[sayac]));
else
std::cout << hmm[sayac];
}
}
}
You should also consider using an std::string instead of an array of char of arbitrary length. Also, take note that you have undefined behavior if the input string does not contain #.

Problem with comparison between pointer and integer C++

I've been getting error messages saying
[Error] ISO C++ forbids comparison between pointer and integer [-fpermissive]
and don't know how to fix it.
I've searched stackoverflow for people with same issues, but only came up with this: c++ compile error: ISO C++ forbids comparison between pointer and integer which didn't answer my question. What also confused me is that the error is on line indicated by the HERE comment, which is the if statement, but I don't see any integers in the condition part.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
int main() {
char in[100];
gets(in);
int len = strlen(in);
std::string s(in);
int count = 0;
for (int i = 0; i < len; i++) {
if (s.at(i) == " ") { // <-- HERE
count += 1;
}
}
cout << count;
}
Say the input is Hello World, I am expecting output to be 1, but I didn't get any output.
The expression " " is a string literal with type const char [2].
The expression s.at(i) returns a char&.
So, s.at(i) == " " is trying to find an equality operator taking
char& on the left and a reference to the literal array const char(&)[4] on the right.
It finds one or more candidates for operator==, but the argument types don't match any exactly, so next it tries the implicit conversion sequences - this is where the char& undergoes integral promotion to int, and the array decays to const char*.
It still doesn't find a match with these, and gives up, but that explains why it has int and const char * arguments when the error is emitted.
All that is a long way of saying that you write character literals like ' ' in C++. They're not just a string of length 1 as in some other languages (and you can't write strings with single quotes at all).
Change the if statement
if (s.at(i) == ' ') {
count += 1;
}
since s.at(i) returns char&, " " is a string, and ' ' is a char.
The problem is that " " is a string literal not a character! A character literal would be ' '.
The error is a bit misleading, because " " is acutally a const char*.
C++ differentiates between character strings and single characters in the literals by different quoting symbols (" vs '). The " " in your code is the string literal that contains one space, a single space character would be written as ' '. The function std::string::at returns a single character.
A small example will show you how the compiler looks on that
#include <iostream>
#include <string>
#include <typeinfo> // for typeid
using namespace std;
int main() {
string s = "Hello, world!";
cout << typeid(" ").name() << endl;
cout << typeid(' ').name() << endl;
cout << typeid(s.at(0)).name() << endl;
return 0;
}
see online demo of above code.
But, to be precise, identical types aren't required for comparisons in C++, but the types need to be compatible. Pointers (string literals are considered constant pointers to characters, in fact pointing to the first character in the literal) and integers (to which char is promoted in your case) are not compatible. To "fix" your problem quickly, change s.at(i) == " " to s.at(i) == ' ', but your program will remain problematic: it still contains a lot of C code that's problematic in it self, too. A possible C++ version could be this:
#include <iostream>
#include <string>
using namespace std;
int main() {
int count = 0;
string line;
std::getline(cin, line);
for (const auto c: line) {
if (c == ' ') {
count++;
}
}
cout << "Your input \""<< line << "\" contains " << count << " space(s)." << endl;
return 0;
}

Using toupper on char returns the ascii number of the char, not the character?

int main()
{
char hmm[1000];
cin.getline(hmm, 1000);
cout << hmm << endl; //this was to test if I could assign my input to the array properly
for (int sayac = 0; hmm[sayac] != '#'; sayac++) {
if (!isdigit(hmm[sayac])) {
if (islower(hmm[sayac]))
cout << toupper(hmm[sayac]);
else if (isupper(hmm[sayac]))
cout << tolower(hmm[sayac]);
else
cout << hmm[sayac];
}
}
"Write a program that reads keyboard input to the # symbol and that echoes the input
except for digits, converting each uppercase character to lowercase, and vice versa.
(Don’t forget the cctype family.) "
I'm doing this exercise from the primer book. But when I run it, it returns the ascii order of the char, not the uppercase/lowercase version of the character. Couldn't figure out the problem. Can someone tell my why please?
(I may have other problems about the exercise, please don't correct them if I have. I want to fix it on my own (except the problem I explained), but I can't check the other ones as I have this problem.
When writing
std::cout << toupper('a');
the following happen:
int toupper(int ch) is called, and returns an integer whose value is 'A' (0x41).
std::basic_ostream::operator<<(std::cout, 0x41) is called, that is the int (2) overload since an int was provided.
Overall, it prints "65".
As a solution, you can cast back your upper case to a char:
std::cout << static_cast<char>(toupper('a'));
It's a question of representation. There is no difference between a character and that character's numeric value. It's all in how you choose to display it. For example, the character 'a' is just a constant with a value equal to the character's numeric value.
The problem you are having is that std::toupper and std::tolower return an int rather than a char. One reason for that is that they handle EOF values, which are not necessarily representable by char. As a consequence, std::cout see you are trying to print an int and not a char. The standard behavior for streaming an int is to print the number. The solution is then to cast your result to char to force the value to be interpreted as a character. You can use something like std::cout << static_cast<char>(std::toupper(hmm[sayac]));.
Try the following :
#include <cctype>
#include <iostream>
int main()
{
char hmm[1000];
std::cin.getline(hmm, 1000);
std::cout << hmm << std::endl; //this was to test if I could assign my input to the array properly
for (int sayac = 0; hmm[sayac] != '#'; sayac++) {
if (!std::isdigit(hmm[sayac])) {
if (std::islower(hmm[sayac]))
std::cout << static_cast<char>(std::toupper(hmm[sayac]));
else if (isupper(hmm[sayac]))
std::cout << static_cast<char>(std::tolower(hmm[sayac]));
else
std::cout << hmm[sayac];
}
}
}
You should also consider using an std::string instead of an array of char of arbitrary length. Also, take note that you have undefined behavior if the input string does not contain #.

Iterating through characters of a string stored in a vector to replace characters C++

So we got an optional assignment in our C++ class. The assignment is basically this:
Write a program that holds a string of at least 8 words.
Do the following:
1. Replace the letters of first word with '?'
2. Turn the letters of the last word to uppercase
We did not yet study vectors in our class.
When I first read the assignment, storing the strings to a vector seemed like a good idea so I went with it.
To replace the characters with a '?' I used a for loop. I know that this would not work if I only had to change only certain characters or every other character to a '?'.
My issue is with converting chars of a string to uppercase.
My thought process was: for loop iterates through all chars in the last word, if the char is lowercase it gets turned to uppercase, if it is already uppercase it does not change.
I believe that my approach could work for this problem, I just maybe did not express myself correctly or I made a silly error somewhere. Could anyone assist me or push me in the right direction?
What other options are there to iterate through all chars of a string stored in a vector? Is there another approach that might work better for this? Thank you for your time.
#include <vector>
#include <cctype>
#include <string>
#include <iostream>
using namespace std;
vector<string>words;
//stores words to vector words
void storeWords()
{
cout << "Input 8 words: " << endl;
string s = " ";
for(int i=0; i<=7; i++)
{
cin >> s;
words.push_back(s);
}
}
//prints our words
void printWords()
{
cout << "\n Words stored in vector: " << endl;
for (const string s : words)
cout << s << endl;
}
//replaces chars of the first word with a '?' sign
void replace1(vector<string>&v)
{
cout << "\nReplaced characters of the first word " << words[0] << " with '?'" << endl;
for (char c : words[0])
cout << "?";
}
void replace2(vector<string>&v)
{
for (char c : words[7])
{
if(islower(c))
c = toupper(c);
}
cout << endl;
cout << words[7]<<endl;
}
int main()
{
storeWords();
printWords();
replace1(words);
replace2(words);
return 0;
}
c = toupper(c) will assign c the uppercase value. However, changing c will not change what's inside words[7]. You can get around this by referencing the char directly (char &c).
void replace2(vector<string>&v)
{
for (char &c : words[7]) {
c = toUpper(c);
}
cout << endl;
cout << words[7]<<endl;
}
Also note that your requirements are to hold a string of at least 8 words. So words[7] will probably end up looking like words[words.size() - 1].
This
for (char c : words[7])
Should be:
for (char& c : words[7])
The first version modifies a local variable, while the second changes the actual characters in words[7].
The little ampersand (&) makes c a reference to a certain character in words[7], allowing you to change c as you would words[7][some_i].
Also, I should add that your replace functions do not need that vector argument.
Ideone Example with that change

Typecasting, ints and chars in c++

I'm trying to write a function to detect separators as defined by an assignment and I know it is not good programming style to
#define EXCLAMATION_POINT 33, but to instead do #define EXCLAMATION_POINT '!'
This is my code:
#include <iostream>
#include <ostream>
using namespace std;
#define PERIOD '.'
#define QUESTION_MARK '?'
#define EXCLAMATION_POINT '!'
#define COMMA ','
#define COLON ':'
#define SEMICOLON ';'
inline bool IsSeparator(int x)
{
if (isspace(x) ||
x == PERIOD ||
x == QUESTION_MARK ||
x == EXCLAMATION_POINT ||
x == COMMA ||
x == COLON ||
x == SEMICOLON) {
return true;
}
else {
return false;
}
}
int main (int argc, char * const argv[]) {
int input;
cout << "Enter characters: \n";
input = cin.get();
if (!IsSeparator(input))
cout << "true";
else {
cout << "false";
}
return 0;
}
But in my IsSeparator(), how do I typecast that int to a char to be compared to '!'. I thought if I did something like (char)EXCLAMATION_POINT that would work, but it does not and the value is left at an int. What am I doing wrong here? Thanks!
You don't need any cast, but:
if (!IsSeparator(input))
should be:
if (IsSeparator(input))
Also, your prompt:
cout << "Enter characters: \n";
implies you can enter multiple characters. So you can, but cin.get() will only read one.
Regarding giving symbolic names to things. Suppose you are parsing a file where the separator is a colon. It then makes sense to say:
const char SEPARATOR = ':';
because you can then change it when the file format changes, for example to:
const char SEPARATOR = '|';
but it doesn't normally make sense to give your own names to the members of the ASCII (or whatever) character set.
In your code, it might make sense to create an array of separators (I'm not showing all the ones you use for my ease of typing):
const char SEPARATORS[] = {':', '|', '!', 0 };
and then have your validation function iterate over the array. Note in this case, the array could also have been expressed as a string literal:
const char * const SEPARATORS = ":|!";
What gives you the idea that those #defines are a good practice at all? Are you required to handle the great Exclamation Mark Redefinition of 2015?
It is probably safe to assume that an exclamation mark is going to be represented by '!' now and forever. Just like the constant one is going to be represented by 1 tomorrow as well.
You don't need to define EXCLAMATION_MARK any more than you need to define ONE or MINUS or INT.