Palindrome tester has logic flaws - c++

This is just a basic palindrome tester for my C++ class, and there appears to be issues.
I already know that I have two separate flaws in here somewhere. At least one, I strongly suspect, is a logic issue. The first problem is that it runs fine the first time through, but when the loop initiates, it doesn't ask for user input to put in a new line to test as a palindrome, it simply retests the old one. The second issue is, I assume, that it is testing spaces, which I base off the fact that it's giving 'hannah' back as good, but 'never even or odd' comes back bad. This one I just don't know how to fix.
#include <iostream>
#include <string>
using namespace std;
int main()
{
bool repeater = true;
do
{
string palindroneCheck;
bool palindronity = true;
cout << "Please enter a line to test for palindromity.\n";
getline(cin, palindroneCheck);
int stringSize = palindroneCheck.size();
int cutOff = stringSize/2;
for (int palindroneLength = 0; palindroneLength < cutOff; palindroneLength++)
{
if (palindroneCheck[palindroneLength] != palindroneCheck[stringSize - palindroneLength -1])
{palindronity = false;
break;}
}
if(palindronity == true)
cout << "Congratulations! This line is a palindrone!\n\n";
else
cout << "Sorry, but this is not a palindrone.\n\n";
palindroneCheck.clear();
char repeat;
cout << "Would you like to try another line? Y/N\n";
cin >> repeat;
if (repeat == "n" || repeat == "N")
repeater = false;
} while (repeater == true);
}

OK, you are right about the spaces. Your code will demand that spaces are in the same location like every other character.
The other bug seems more subtle: it's where you ask to repeat or not.
Why? Because it asks, you enter 'n' and then 'enter'
The cin >> repeat only reads the 'n', but not the 'enter'
so the next time you do `readline(cin,PalindromCheck)' it will read an empty string.
Try to write palindromCheck just after reading it. You'll see.

The reading issue of getline is solved by comments. For the whitespaces, you can tackle it by removing all the spaces inside string palindroneCheck,
std::string::iterator new_end = std::remove(palindroneCheck.begin(), palindroneCheck.end(), ' ');
std::string palindroneCheckWithoutSpaces(palindroneCheck.begin(), new_end);
Then you use palindroneCheckWithoutSpaces to do the Palindrone test.
int stringSize = palindroneCheckWithoutSpaces.size();
int cutOff = stringSize/2;
for (int palindroneLength = 0; palindroneLength < cutOff; palindroneLength++)
{
if (palindroneCheckWithoutSpaces[palindroneLength] != palindroneCheck[stringSize - palindroneLength -1])
{palindronity = false;
break;}
}
if(palindronity == true)
cout << "Congratulations! This line is a palindrone!\n\n";
else
cout << "Sorry, but this is not a palindrone.\n\n";
(you need header algorithm to use remove)
Update:
std::remove remove an element from the input range (this is defined by begin and end here) based on the value you passed in , here is the whitespace ' '. Then it return the new end of the changed range (since you delete something, the range becomes smaller). The new range starts with begin and ends with the returned value.
So the second line you create a new string based on the new range.

Related

Unable to detect enter key in C++

Now, before this question gets marked for duplicate. I have already gone through most of the questions and their relative answers of C++. These are the links that I have tried and none of them work for me. It maybe because they are using an older version of C++, and I have the latest version of C++. Here are the links that I have tried:
Detecting ENTER key in C++
https://www.sololearn.com/Discuss/1863352/how-can-i-check-that-user-press-enter-key-in-c
http://www.cplusplus.com/forum/beginner/2624/
https://www.dreamincode.net/forums/topic/398680-detect-enter-key/
Now, with the duplicates out of the way. I am making an expression calculator. So, for example if the user input is: 2+2*6*9/9, then the output should be 14.
The code where I suspect that the problem lies is in:
#include <iostream>
#include <vector>
using std::cout;
using std::cin;
using std::string;
using std::vector;
void clear();
void error(string message);
int main() {
cout << "Enter an expression: ";
double l_Value = 0, r_Value = 0, result = 0, count = 0, previous_number;
char op;
while (cin >> l_Value) { // 1+2*3+6-4/2+3
if (!cin) {
error("Invalid operand entered!");
}
else {
bool is_Error = 0; // false
vector<double> numbers;
numbers.push_back(l_Value);
previous_number = l_Value;
while (cin >> op) {
if (op == '\0') {
break;
}
cin >> r_Value;
switch (op)
{
case '+':
numbers.push_back(r_Value);
previous_number = r_Value;
break;
case '-':
numbers.push_back((-1 * r_Value));
previous_number = (-1 * r_Value);
break;
case '*':
numbers.pop_back(); // take out the number
r_Value *= previous_number;
numbers.push_back(r_Value);
previous_number = r_Value;
break;
case '/':
if (r_Value == 0) {
error("Sorry, division by zero has occured. Please re-evaluate your expression!\n");
is_Error = 1; // true
break;
}
else {
numbers.pop_back(); // take out the number
previous_number /= r_Value;
numbers.push_back(previous_number);
break;
}
}
}
if (!is_Error) {
for (int i = 0; i < numbers.size(); i++) {
result += numbers[i];
}
cout << result << '\n';
}
numbers.clear();
result = 0;
l_Value = 0;
r_Value = 0;
}
cout << "Enter an expression: ";
}
clear();
return 0;
}
None of the links above seemed to work for me.
When I press the Enter key, it expects me to give another input, and that is not supposed to happen. So when I used cin.get() == 'n' or cin.get() == (int)'\n', it expects for another input. But, when I have an 'x' at the end of the expression, it works perfectly fine. So, I need the "cin" operator to help me detect an Enter character at the end of the expression and then terminate the program.
Here, is a sample run of a program with 'x':
[![running as x-terminator][1]][1]
[1]: https://i.stack.imgur.com/ORPQa.png
When I try the above solution such as "cin.get() == '\n':
Then, I thought that maybe it is reading the null character and so, I tried if (op == '\0'):
For the enter key and null character I had to press Ctrl+Z to terminate the program. Please help!
As, mentioned by user #idclev, I already have a string program that works, but I am trying to avoid using string to calculate any expressions! So, if I could detect an enter key pressed using a character datatype that would be great!
I avoided strings to avoid parsing through the text
That argument is moot. What you can read from cin you can also read from a std::string, no difference whatsoever. You just need to add one step:
#include <iostream>
#include <string>
#include <sstream>
int main( ){
std::string x;
std::cin >> x;
if (x == "") {
std::cout << "user pressed enter (and nothing else)";
} else {
double y;
std::stringstream ss{x};
ss >> y;
std::cout << y;
}
}
This will read one std::string. If user only hit enter then the string will be empty. If the user entered something the else branch will be taken and you can extract the number from the string in the same way you did extract the number from cin (via using a std::stringstream).
If you have more than one number in the input you need to use getline to read the string, because cin will (by default) only read till the next whitespace.
Again...
If I used a string, I would have a tough time in extracting single-digit and two-digit or n-number of digits in a string. The double data type does that for me
You can read single-digit or any number of digits from a stringstream in exactly the same way as you read them from cin.
I already made a program with string in it. I was trying to avoid string to see how much faster would it be without string.
It won't be any faster. Constructing the string and the stringstream is maybe in the order of microseconds. A user entering input is in the order of seconds, maybe milliseconds when they are typing very fast.
Your approach cannot work because hitting enter is not considered as a character. Trying to read a character when there is none in the stream will fail. It will not set the character to \n or \r.
On the outer loop, you are trying to read a double, but you keep pressing enter. There is no input to evaluate, so it keeps trying to read a double. You can get out of it by ending the input stream with ^Z, or you can give it any actual content to read, and it will try to make it into a double (which is what your code explicitly told it to wait for).
Basically, when you press enter, it's ignoring it because
http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/
Extracts as many characters as possible from the stream and inserts them into the output sequence controlled by the stream buffer object pointed by sb (if any), until either the input sequence is exhausted or the function fails to insert into the object pointed by sb.
Try experimenting with this to see what is happening.
#include <iostream>
#include <vector>
#include <string>
int main() {
double x;
std::cin >> x;
std::cout << "read this value: " << x << std::endl;
// this is what while or if will look at
bool success = !std::cin.fail();
if (success)
std::cout << "success" << std::endl;
else
std::cout << "failure, loop will exit" << std::endl;
return 0;
}
What you should want (in my opinion) is a function that takes the expression as a string, and returns the result, so you can write unit tests, and make sure the function works. You can use this function with any expression that you can put in a string. It doesn't HAVE to be typed in by a user.
If you want the user to type in the experession, it's a lot easier to just use getline() then pass the string to your function. The big problem with using cin on each variable and character is that the user has no idea which datetype is expected right then. Granted, it's not hard to guess with an expression, but you wrote it and debugged it and still didn't know which cin you were failing to get the right datatype to. (this is normal, btw -- been there, which is why I getline and parse separately)

incrementing a word ahead in 2d array using pointers

I'm writing a program to read a piece of text and put it in the correct grammar. All punctuation marks and newlines in the text are preceded by a ':'. One of the functions of my program is adding spaces between words that are read from the text file. However, I don't want it to do that all the time. Since ':.' marking the end of a sentence is a new word and not part of the previous word, it'll add a space between the last word and the period.
"... at the zoo ."
Instead of this:
"... at the zoo."
I'm trying to write a function that looks at the next word in the array to see if it's a colon.
Here's what I tried, among other things:
int isColon(char madLib[][256], int numWords)
{
numWords++;
char* k = madLib[numWords];
if (*k == ':')
{
cout << "{*k}";
return true;
}
else
return false;
}
Here is the output: {╠}
Without incrementing the counter (numWords), it displays the first letter without any problem.
However, I need it to look to the next word.
What do I do? Any suggestions?
Here is the code that actually displays the text:
int readFile(const char fileName[])
{
ifstream fin(fileName);
//if error when opening file, it will return true
if (fin.fail())
{
return true;
}
char madLib[256][256];
int numWords = 0;
while (fin >> madLib[numWords])
{
bool isSpace = true;
bool noPrint = false;
char* k = madLib[numWords];
while (*k)
{
if (*k == ':')
{
k++;
if (*k == '!')
cout << endl,
isSpace = false;
else if (*k == '.')
cout << ".";
else if (*k == ',')
cout << ", ";
else if (*k == '<')
cout << "\"",
isSpace = false;
else if (*k == '>')
cout << "\" ";
else
displayArray(madLib, numWords),
noPrint = true;
}
else
{
if (noPrint == false)
cout << *k;
}
k++;
}
if (isSpace == true && isColon(madLib, numWords) == false)
cout << " ";
noPrint = false;
numWords++;
}
fin.close();
return 0;
}
In my humble opinion, the main problem is that you are still working in complete C-Style mode. With all errors that result out of that.
You are using pointers and C-Style arrays. Recommendation: Do not and never use raw pointers for owned memory in C++.
Recommendation: Do not use C-style arrays in C++ (or only, if you know what your are doing).
Btw: You are using the wrong syntax for passing an 2d-array (which you should not use in the first place) to your functions. The array is decaying to a pointer.
You have huge risks for out of bounds problems using your magic numbers 256.
But your specific problem is resulting from a wrong design. You read a word, and then, before you have read the next word, you already check this none existing word.
Look at your code. You are doing fin >> something, then operate on this something, then you are calling your subfunction to check the next word. But this has not yet been read.
So, the recommendation is: At first read all words into your array, and then, afterwards, check your array content.
I hope this helps

jumping outside loop in a specific case

I am writing a code that, for one or several lines of strings, find if the overall input has only "cool" (it's first middle and last string are the same) lines, only "uncool" lines or a mix of both.
The problem I'm having is whenever I input an even number the while loop terminates. Debugging I found that, just before jumping out n gets value 0 but I don't understand how this would make the loop end.
This is the code:
#include <iostream>
using namespace std;
int main () {
// Bool has control if we have found a cool line/non-cool line
bool cool = false;
bool uncool = false;
int n; //lenght of input
while (cin >> n) {
if (cool and uncool) break; // we have found one of each so we know it is a mixed input
else if (n%2 == 0) uncool = true; // if the lenght is even there is no middle string
else {
// we are trying to see if the middle and last string are equal to the first
string comparing_string;
cin >> comparing_string;
string rest_of_sequence;
bool this_is_cool = true;
for (int i = n-2; i >= 0; i--) { // we input the rest of strings and compare them to the first
cin >> rest_of_sequence;
if ((i == n/2 or i == 0) and rest_of_sequence != comparing_string) this_is_cool = false;
}
if (this_is_cool) cool = true;
else uncool = true;
}
}
if (cool and uncool) cout << "both types" << endl;
else if (cool and not uncool) cout << "all cool" << endl;
else if (uncool and not cool) cout << "none cool" << endl;
}
Any help is appreciated! I'm currently in first year of uni and always open to recommended books/webpages/videos to continue learning :)
The problem was that I thought the program would just ignore input that wasn't an integer in the while loop, but it doesn't.
Now the code is correct:
else if (n%2 == 0) {// if the lenght is even there is no middle string
uncool = true;
string just_passing_input;
for (int i = n; i > 0; i--) cin >> just_passing_input;
}
Thanks for the helpful feedback, I shall now continue learning.

using strings in C++ // how do i?

I need help changing my current program so that it displays the letters already entered by the user, and displays the letters again immediately before prompting the user to enter another letter. what I have so far is below.
int main()
{
char another = 'Y';
string message = "";
while (toupper(another) == 'Y')
{
cout << "Enter a message: ";
getline(cin, message);
for (int x = 0; x < message.length(); x += 1)
cout << message.substr(x) << endl;
cout << endl << "Another message (Y/N)? ";
cin >> another;
cin.ignore(100, '\n');
}
system("pause");
return 0;
}
If you want all the characters (you entered at any time) printed, you can do the following:
Start off with two empty strings. One is a buffer, that stores the string that's currently added and the other holds all of the strings already added, like so:
string buf = "";
string messages = "";
Read your characters into your buffer, via:
getline(cin, buf);
Append the string to the other messages, already entered:
messages.append(buf);
Append a string delimiter to your messages, so you know which sequence of characters (including whitespaces) belong to the message you entered:
messages.append(";");
(BTW: Using "-quotes here is really important, to let the compiler know you are comparing strings, not characters, as there is no string::append(char s)-method defined, only string::append(string s).)
Iterate through your messages-string, and check if the character at position x is equal to ';' (Using '-quotes here is also important, because string::operator[] return a character not a string!!!). For instance you might code:
for (int x = 0; x < messages.length(); x++) {
//Test if string delimiter is reached, if so, jump to next line.
if(messages[x] == ';') {
std::cout << "\n";
}
//Else just print the string:
else {
std::cout << messages[x];
}
}
Test if another message should be entered.
OR you create a linked list of strings. Adding new strings to the list, every time you enter a new string. This might be the more elegant way to do this, however it is slightly more involved. (I'm assuming you're fairly new to programming, if not I apologize!). Check Wikipedia or cplusplus.com for more info on linked lists!
Hope I could answer your question,
lindebear

while statement is unable to read the correct char input

hi i am new to c++ and i dont understand why my while statement doesnt work now. it was working when i tried to do it earlier.
Full code is available at: http://pastebin.com/aeH5fKwh
basically here is the while loop (i excluded all the unnecessary parts, i left the inside of the while loop intact for viewing purpose)
int main()
{
unsigned int seed;
char input;
bool done;
for (int round = 0; round < 5; round++)
{
done = false;
cout << "\nEnter seed: ";
cin >> seed;
cout << "\nRound 1" << endl;
while(!done)
{
cout << "\nDo you wish to draw another card [y][n]: ";
cin >> input;
while (input != 'y' && input != 'n')
{
cout << "Invalid input! Please enter [y][n]!" << endl;
cin >> input;
}
if (input == 'y')
{
dealExtra(playerHand, deck, gameInfo);
cout << "Your cards are ";
printHand(playerHand, gameInfo.playerCardCount);
}
else
done = true;
}
}
cout << endl;
return 0;
}
when i try entering anything that is not 'y', 'n', it will tell me that my input is invalid. But when i try to enter 'y' or 'n', it kinda just ignored it and nothing else happened.. i checked with cout statement and found that it manage to get into the if (input == 'y') statement, but it doesnt seem like it is doing anything else. Everything was fine till 20 minutes ago and i really couldnt figure out whats wrong.
Edit: i ran another test using "cout << '[' << input << ']' << endl;".. it seems like the program is able to get my first input, but then it just hangs there afterwards.. what i get is something like:
Do you wish to draw another card [y][n]: y
[y]
y
y
y
y
I compiled this on linux terminal using g++
if extra codes is needed, i'll edit and add them.. thanks!
When you ask for input from the console, most implementations buffer characters until a newline key is pressed.
After the newline is received, the first character of the buffer is returned. The newline still remains in the buffer as well as any extra characters.
In your case, the second cin >> input statement will read the newline from the buffer.
As an experiment, try entering "frog" and single step through your program. This should illustrate the case of residual characters in the buffer.
Try cin.ignore(1000, '\n') after the first cin >> input. The ignore method will eat up any remaining characters in the buffer until the newline is found.
Make below statements inactive
dealExtra(playerHand, deck, gameInfo);
printHand(playerHand, gameInfo.playerCardCount);
and check if it works, then try making one of the above statements active alternately to find out in which function the flow is getting lost. And so on.
If you feel lazy to run a debugger, and plan to use cout<< statements to find a hanging call, you should flush you cout:
( cout << "I am here and going to hang" ).flush() ;
Otherwise you can't see recent output just because it's still in the output buffer. Try this and you well might see what call hangs your program.
You have an infinite loop inside checkComputerHand:
bool done = false;
while(!done)
{
if(sum == 11 && checkAce == true)
{
computerHand[aceLocation].value = 11;
done = true;
}
if(sum > 11 && checkAce == true)
{
computerHand[aceLocation].value = 1;
done = true;
}
// What if checkAce wasn't true? Infinite loop!
}
Also, the first two lines of newGame do not make any sense:
void newGame(Card playerHand[], Card computerHand[], Statistics &gameInfo)
{
playerHand = '\0';
computerHand = '\0';
// ...
}
Array parameters are silently rewritten by the compiler as pointer parameters. So all you're doing is assigning the null pointer to those local pointers. Probably not what you intended...