I have a program that queries the user for string inputs that are stored in a 2D char array. The program should stop asking for inputs when 20 strings are entered or when the user hits enter twice.
For some reason no matter what I do, the program will keep displaying all empty strings even though the user hasn't populated them. How can I stop this?
int main()
{
char sentences[20][81] = { '\0' };
cout << "Enter up to 20 sentences - when done, Press ENTER: ";
input(sentences);
for (int i = 0; i < 20; i++)
{
if (sentences[i] == '\0' || sentences[i] == "\n")
break;
else
{
cout << "\nHere is sentence " << i + 1 << ": " << endl << sentences[i] << endl;
menu(sentences[i]);
}
}
cout << "\nPress any key to continue...";
_getch();
return 0;
}
void input(char str[20][81])
{
for (int i = 0; i < 20; i++)
{
cin.getline(str[i], 81, '\n');
if (str[i][0] == '\0')
break;
}
}
There are no error messages, and I expect that the check here
if (sentences[i] == '\0' || sentences[i] == "\n"
break;
should end the program when a blank c-string is encountered, why isn't that happening?
This check here is wrong:
if (sentences[i] == '\0' || sentences[i] == "\n")
You're comparing sentences[i] (a char*) with '\0' (a char). The sentences[i] == "\n" part is entirely wrong - just get rid of that. Your check should look like this:
if (sentences[i][0] == '\0' )
But I would really recommend just using a std::vector<std::string> instead of this multidimensional c-style string construct. You can just use push_back to add a string to the vector and range-based for loop to go through the vector and print its results. You can do this with your input function like this:
void input(std::vector<std::string> &sentences)
{
for (int i = 0; i < 20; i++)
{
std::string s;
std::getline(std::cin, s);
if (s.empty())
break;
sentences.push_back(s);
}
}
And then the main function like that:
int main()
{
std::vector<std::string> sentences;
std::cout << "Enter up to 20 sentences - when done, Press ENTER: " << std::endl;
input(sentences);
for (int i = 0; i < sentences.size(); i++)
std::cout << "Here is sentence " << i + 1 << ": " << std::endl << sentences[i] << std::endl;
std::cout << "Press any key to continue...";
//getch();
return 0;
}
This way you wouldn't even need the hard-coded limit of 20 sentences, you could just remove it and have a while (true) loop instead.
Related
I have a function that receives a character "x" from a user. If the "x" exists in a hard-coded array, "x" is pushed into another array filled with lowdashes in the same position as in the first array. Fo example:
firstArray = ["h", "e", "l", "l","o"]
//user provided character that exist in first array. "e"
lowDashesArray= ["_", "e", "l", "l", "o"]
Then, I want to check if both arrays are equal, my problem is that when the user guesses the firts element in the array (in the above example "h"), the for loop stops iteraring without checking if the other elements are equal. As a result, the block of code that expects both arrays to be equal is executed.
The function looks like so:
bool checkIfLetterExistOnWord(string word, char letter, char* lettersArray, char* lowDashesArray, bool hasWon, bool hasLost, int lives){
bool isCorrectLetter = false;
for(int i = 0; i<word.length(); i++ ){
if(letter == lettersArray[i]){
int position = i;
lowDashesArray[position] = letter;
cout << lowDashesArray;
cout << endl;
isCorrectLetter = true;
}
}
if(isCorrectLetter){
for(int j = 0; j < word.length(); j++){
if(lettersArray[j] == lowDashesArray[j]){
hasWon = true;
//here is the problem. But only when user guesses the first element of the array
}
else{
break;
}
}
if(hasWon){
cout << "You have won";
cout << endl;
cout << hasWon;
cout << endl;
cout << lowDashesArray;
cout << endl;
cout << word;
cout << endl;
return hasWon;
}
else{
cout << "good job. Guess the next letter";
cout << endl;
return hasWon;
}
}
else{
cout << "wrong";
cout << endl;
lives--;
if(lives == 0){
hasLost = true;
cout << "You lost";
return hasLost;
}
else {
cout << "You still have this lives :";
cout << endl;
cout << lives;
cout << endl;
return hasLost;
}
}
}
Both your loop logic is incorrect.
bool isCorrectLetter = false;
for(int i = 0; i<word.length(); i++ ){
if(letter == lettersArray[i]){
int position = i;
lowDashesArray[position] = letter;
cout << lowDashesArray;
cout << endl;
isCorrectLetter = true;
}
}
Here you print the array once for every occurance of the guess character. FUrthermore you do not check, if the letter "was already uncovered". You need to do the printing after the loop and depending on whether you want guessing uncovered chars to be an error, you may need to ajust the check.
for(int j = 0; j < word.length(); j++){
if(lettersArray[j] == lowDashesArray[j]){
hasWon = true;
//here is the problem. But only when user guesses the first element of the array
}
else{
break;
}
}
You're trying to check here, if every char meets a certain criterion (being a non placeholder char). In this case you cannot break early. In general the loop for this kind of check needs to look like this:
bool checkSuccess = true;
for (size_t i = 0; checkSuccess && i != length; ++i)
{
if (!Check(elements[i]))
{
checkSuccess = false;
}
}
Or in your case (using break instead):
hasWon = true;
for(int j = 0; j < word.length(); j++)
{
if(lettersArray[j] != lowDashesArray[j])
{
hasWon = false;
break;
}
}
Imho it's preferrable to separate the replacement logic from io logic. You could e.g. rewrite the logic similar to this:
constexpr char MaskChar = '_';
/**
* Replaces placeholders in \p maskedText, if they the corresponding char in \p clearText
* matches \p guess.
*
* \param[in,out] maskedText the text with some chars replaced with '_'
*
* \return true, if at least one char was replaced, false otherwise
*/
bool GuessChar(std::string const& clearText, std::string& maskedText, char const guess)
{
assert(clearText.length() == maskedText.length());
bool guessCorrect = false;
for (size_t i = 0; i != clearText.length(); ++i)
{
if (maskedText[i] == MaskChar && clearText[i] == guess)
{
guessCorrect = true;
maskedText[i] = guess;
}
}
return guessCorrect;
}
int main()
{
std::string const clearText = "hello";
std::string maskedText(clearText.length(), MaskChar);
size_t lives = 3;
while (lives > 0 && maskedText.find(MaskChar) != std::string::npos)
{
std::cout << "Word: " << maskedText
<< "\nMake your guess!\n";
char c;
std::cin >> c;
if (GuessChar(clearText, maskedText, c))
{
std::cout << "Guess correct!\n";
}
else
{
--lives;
std::cout << "Guess incorrect\n"
<< lives << " lives left\n";
}
}
if (lives > 0)
{
std::cout << "You win!\n";
}
else
{
std::cout << "You loose!\n";
}
}
For anyone that might be able to help me figure this out. I am creating a method that will compare two strings and detect whether they are an anagram or not. An anagram is two strings that have the same letters, though they may be in a different order. For example "listen" and "iltsen" are anagrams.
I have decided to break the strings up into char arrays. I know that is working correctly because I tested it using cout on each array element. Next is where it goes wrong. I attempt to use the ASCII value of each char and add it to a variable for each array. This would mean that if the values match then they must be an anagram.
However for whatever unknown reason it is not working correctly. I am finding that it is reading index 0 twice for one array and not for the other. I am so confused beyond reason. I have absolutely no idea what this is occurring. I have tried multiple different solutions and had no luck finding out the problem. If anyone has any idea whats going on here I would greatly appreciate the help.
-Thanks!
#include "stdafx.h"
#include <iostream>
#include <string>
#include <math.h>
#include <iomanip>
#include <cctype>
#include <vector>
using namespace std;
bool isAnagram(string s1,string s2)
{
static char firstString[] = { 'c' };
static char secondString[] = { 'c' };
int size = s1.length();
static int count1 = 0;
static int count2 = 0;
cout << s1 << endl;
cout << s2 << endl;
if (s1.length() == s2.length())
{
for (int i = 0; i < size; i++)
{
firstString[i] = s1.at(i);
cout << i;
}
for (int i = 0; i < size; i++)
{
secondString[i] = s2.at(i);
cout << i;
}
cout << endl;
for (int i = 0; i < size; i++)
{
count1 = count1 + (int)firstString[i];
cout << "first" << i << ": " << firstString[i] << " = " << (int)firstString[i] << endl;
count2 = count2 + (int)secondString[i];
cout << "second" << i << ": " << secondString[i] << " = " << (int)secondString[i] << endl;
}
cout << count1 << " and " << count2 << endl;
if (count1 == count2)
return true;
}
else
return false;
count1 = 0;
count2 = 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
static char end;
do
{
string s1;
string s2;
cout << "Please enter the first string: ";
cin >> s1;
cout << endl << "Please enter the second string: ";
cin >> s2;
bool result = isAnagram(s1, s2);
static string resultString;
if (result == true)
resultString = "True";
else
resultString = "False";
cout << endl << "Anagram test result: " << resultString << endl;
cout << endl << "enter E for end or any other key to run again: ";
cin >> end;
cout << "----------------------------------------" << endl;
} while (end != 'e' && end != 'E');
return 0;
}
It's not useful to use static variables in your case, without them you wouldn't need the last 2 lines of isAnagram.
It's also useless to store both strings in char arrays because you can use them directly in your 3rd loop(also you are overflowing your buffer which has a size of 1)
for (int i = 0; i < size; i++)
{
std::cout << count1 << " ";
count1 = count1 + (int)s1.at(i);
cout << "first" << i << ": " << s1.at(i) << " = " << (int)s1.at(i) << endl;
count2 = count2 + (int)s2.at(i);
cout << "second" << i << ": " << s2.at(i) << " = " << (int)s2.at(i) << endl;
}
Also you can't say that 2 strings do contain the same letters by comparing the sum of their ASCII values, thats like saying 3 + 4 is the same as 2 + 5 because both give 7.
You could create an array of 52 ints, each element is a counter for its own letter, then you could loop over both strings with one loop where each letter of the first string is incrementing its element in the array and the second strings letters are decrementing elements.
if (s1.length() != s2.length())
return false;
std::vector<int> counts(52);
for (unsigned int i = 0; i < s1.length(); ++i)
{
++counts[s1[i] - (s1[i] < 91 ? 65 : 71)];
--counts[s2[i] - (s2[i] < 91 ? 65 : 71)];
}
be sure that the array is initialized to 0.
At the end you need to loop over the array, if one of the elements is not 0 it's not an anagram, else return true.
for (unsigned int i = 0; i < 52; ++i)
if (counts[i] != 0)
return false;
return true;
I am working on a hangman game where incorrect letter guesses are stored in a char array called wrongletters. Of course, the user begins the game with zero wrongletters, so the wrongletters array remains empty upon declaration. The problem I am having is that when I try to display the wrong letters, the letters are spaced very far to the right because of all the other non-value elements in the array
Intended: (Guessed Letters: A B C D)
Current: (Guessed Letters: (Extra Spaces) A B C D)
Any thoughts? (I am aware game does not function properly yet):
void gameSequence() // Runs the hangman game loop
{
// Local and Global Variable Declaration and Initialization
char guessLetter = ' ';
guessWord = strToUpper(getNextWord());
string maskedWord(guessWord.size(), '_');
char wrongLetters[26] = {};
int numWrongLetters = sizeof(wrongLetters) / sizeof(wrongLetters[0]);
// Input, Process, and Output
cout << "\nLet's PLAY\n\n";
for (int i = 0; i < maskedWord.length(); i++)
cout << maskedWord[i] << " ";
while (incorrectCount < 6)
{
drawHangman(incorrectCount);
cout << "<<<<<<<<<< MAKE A GUESS >>>>>>>>>>\n\n";
cout << "Guessed Letters: ";
for (int i = 0; i < 26; i++)
cout << wrongLetters[i] << " ";
cout << "\n\nEnter a letter to guess: ";
cin >> guessLetter;
cout << endl;
guessLetter = toupper(guessLetter);
for (int i = 0; i < maskedWord.length(); i++)
cout << maskedWord[i] << " ";
if (guessWord.find(guessLetter) != string::npos)
{
for (int i = 0; i < maskedWord.length(); i++)
{
if (maskedWord[i] == guessLetter)
maskedWord[i] = guessLetter;
}
}
else
{
incorrectCount++;
wrongLetters[incorrectCount] = guessLetter;
bubbleSort(wrongLetters, numWrongLetters);
}
if (incorrectCount == 6)
{
drawHangman(incorrectCount);
cout << "Sorry you lose - the word was: " << guessWord << endl << endl;
}
}
incorrectCount = 0;
}
As I understand the array wrongletters contain at the beginning it of the wrong letters guesed so far. So there is no point of print all of it and especially sort all of it.
Hence you should change:
for (int i = 0; i < incorrectCount; i++) // incorrectCount replaced 26
cout << wrongLetters[i] << " ";
...
else
{
incorrectCount++;
wrongLetters[incorrectCount] = guessLetter;
bubbleSort(wrongLetters, incorrectCount+1); // incorrectCount replaced numWrongLetters
}
Otherwise when you sort all of the array the spaces go first before the wrong letters.
Because even if your char sequence is empty, you ask in your loop to display a space after the wrongLetters[i]. Replace the ' ' by endl and you will have
A
B
C
D
The task is pretty simple: create a program that will tell the user if a sentence he or she enters is the same backwards and forwards (in terms of words used, not spelling). For example, "I am that am I" (please ignore how grammatically nonsensical this may be). So I decided to create two string vectors - one that would store the original sentence, and another that would be the sentence reversed. The elements of each vector would be strings containing the words of the sentence, e.g ["I", "am", "that", "am", I"], excluding any spaces in the string.
I'm stuck in a preliminary state of solving this problem - comparing the elements of these two vectors. Here's my code below (note that sentence is the first vector, and reverseString is the second vector, containing the elements in reverse order):
for (int i = 0; i < sentence.size(); i++) {
// The below output is for debugging purposes
cout << "The index is " << i
<< " and the original string at this location is " << sentence[i]
<< " and the reverse string is " << reverseString[i] << endl;
if (sentence[i] == reverseString[i]) {
cout << reverseString[i] << "---" << sentence[i] << endl;
cout << "A match!" << endl;
} else {
cout << reverseString[i] << "---" << sentence[i] << endl;
cout << "Not a match!" << endl;
}
}
Bizarrely, the above code seems to work accurately for elements in indexes 1 to vector.size()-2 (remember that indexes in vectors for c++ begin and zero). But index 0 or vector.size()-1 - i.e. the first and last elements of each vector - always yields a "Not a match!", no matter what the sentence. Everything in between is accurately compared, but those two positions aren't.
This is a very strange bug. Maybe my error lies in creating the second vector? This is the code I used:
int t = sentence.size() - 1;
for (int i = 0; i < sentence.size(); i++) {
reverseString[i] = sentence[t];
t--;
}
Am I inadvertently mutating something I shouldn't be for the first and last elements, in a way I can't quite see? Is my logic flawed? Please let me know what you think :)
EDIT: I am posting a Minimal, Complete, and Verifiable Example of my code below:
#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
int main() {
string input;
cout << "Please input a sentence - no preceding or trailing spaces."
" It will be analyzed accordingly: ";
getline(cin, input);
string secondString = "";
secondString[0] = input[0];
int i = 0;
for (i = 0; i <= input.length(); i++) {
// the below strips a string of punctuation if there is any,
// as these characters would mess up the comparison.
if (input[i] == ',' || input[i] == ';' || input[i] == ':' ||
input[i] == '.' || input[i] == '?' || input[i] == '!') {
} else {
secondString = secondString + input[i];
}
}
// now stuff the individual words in the string into a vector
vector<string> sentence;
// now we are going to stuff each word into a vector
string word;
stringstream ss(secondString);
while (getline(ss, word, ' ')) {
sentence.push_back(word);
}
// now for Task 1 - we will create a second vector that is reversed.
// Then compare both vectors - if identical, note it.
vector<string> reverseString;
reverseString = sentence;
int t = sentence.size() - 1;
for (int i = 0; i < sentence.size(); i++) {
reverseString[i] = sentence[t];
t--;
}
for (int i = 0; i < sentence.size(); i++) {
cout << "The index is " << i
<< " and the original string at this location is " << sentence[i]
<< " and the reverse string is " << reverseString[i] << endl;
if (sentence[i] == reverseString[i]) {
cout << reverseString[i] << "---" << sentence[i] << endl;
cout << "A match!" << endl;
} else {
cout << reverseString[i] << "---" << sentence[i] << endl;
cout << "Not a match!" << endl;
}
}
return 0;
}
You have undefined behaviour because of the comparison in this line:
for (i = 0; i <= input.length(); i++)
Undefined behaviour happens as soon as the loop body tries to access input[i] while i is equal to input.length(). Make it:
for (i = 0; i < input.length(); i++)
It's just bad luck that the program didn't crash, or else you may have noticed the error earlier.
What happened to me when I tried it was that a superfluous space character was attached to secondString, which eventually caused the last element in sentence to have an extra space at the end, so the first and last words could never be equal.
Also note that the sentence-comparison code itself is too complicated, because you can achieve your goal in a much simpler manner with std::equal, std::vector's reverse iterator obtained by the rbegin() member function, and splitting the range in half, like in this example:
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
bool compare(std::vector<std::string> const& sentence)
{
// returns true if the range from the first to the middle element
// is equal to the range from the last to the middle element
return std::equal(
sentence.begin(),
sentence.begin() + sentence.size() / 2,
sentence.rbegin()
);
}
int main()
{
std::vector<std::string> const sentence1 = { "I", "am", "that", "am", "I" };
std::vector<std::string> const sentence2 = { "am", "that", "am", "I" };
std::vector<std::string> const sentence3 = { };
std::vector<std::string> const sentence4 = { "I", "am", "that", "that", "am", "I" };
std::vector<std::string> const sentence5 = { "I" };
std::cout << compare(sentence1) << "\n"; // true
std::cout << compare(sentence2) << "\n"; // false
std::cout << compare(sentence3) << "\n"; // true
std::cout << compare(sentence4) << "\n"; // true
std::cout << compare(sentence5) << "\n"; // true
}
This solution takes only one std::vector and does not perform more comparisons than necessary; when the middle element of a sentence is reached, the result is already known.
In contrast, your original code needlessly iterates the entire sentence:
for (int i = 0; i < sentence.size(); i++) {
For one thing, secondString[0] = input[0];is invalid when secondString
is empty. Likewise for (i = 0; i <= input.length(); should stop before
reaching input.length(). – Bo Persson 12 mins ago
Bo Persson's comment fixes your problem.
I am having a bug that I cannot find a fix for through google searching. I am attempting to make a text based version of the game Mastermind. I am using a string the is set from an array of chars as the criteria for a while loop. When the string is equal to "****" the game is supposed to tell the player that they won and exit, but for some reason a ^A is being added on to the end of the string that is being checked, even though it is not in the char array.
Here is the function that sets the char array and returns a string from that array:
string check(int guess[4], int num[4]) {
char hints[4];
cout << " ";
for (int i = 0; i < 4; i++) {
if (guess[i] == num[i]) {
hints[i] = '*';
cout << "*";
}
else {
for (int x = 0; x < 4; x++) {
if (guess[i] == num[x]) {
cout << "+";
}
}
}
if (guess[i] != num[i]) {
hints[i] = ' ';
}
}
string hint(hints);
cout << endl;
cout << hint << endl;
return hint;
}
And here is the function checking the value of the string:
while (hints.compare("****") != 0) {
if (guessCount == 5) {
break;
}
cout << "Guess?: ";
cin >> guess;
intToArray(guess, guessArr);
hints = check(guessArr, nums);
cout << hints << endl;
guessCount++;
}
if (hints.compare("****") == 0) {
cout << "You win! The number was: ";
for (int i = 0; i < 4; i++) {
cout << nums[i];
}
}
You haven't null-terminated the hints array, so you are getting extra garbage that is lying around on the stack in your string.
You could let the hint string know how long it is when you are constructing it.
string hint(hints, 4);
cout << endl;
cout << hint << endl;