Program soft-locking when calling second* function - c++
So, I'm practising my C++ code by writing a program that creates a matching-pairs game out of a grid with user-specified size. To do this I've separated each action (initialising the grid, drawing the grid, hiding the pairs and finding the pairs from user input) into a function.
Unfortunately, at some point - I can't tell when or how - the program began failing to call the second* and subsequent functions. After calling drawGrid, it should move on to hidePairs immediately - however, it just stops at that step. The cursor in the command window keeps blinking, so the program's running just fine, but nothing I can do will make it progress.
I've checked via debugging, and it does successfully execute drawGridand moves on to the next line in main, but then no more code gets executed. What am I doing wrong?
*EDIT: third function, it successfully draws the grid, THEN stops before hiding the pairs. Unnecessary calls-by-reference removed and all functions added for clarity. My bad :P
#include <iostream>
#include <random>
#include <algorithm>
void drawGrid(int gridX, int gridY, char gridArray[][30]);
void hidePairs(int gridX, int gridY, char pairsArray[][30], int *numPairs);
void findPairs(int gridX, int gridY, char gridArray[][30], char pairsArray[][30], int *numPairs);
void initialiseGrid(int gridX, int gridY, char gridArray[][30], char pairsArray[][30]);
int main()
{
int gridX, gridY, numPairs;
//Ask user for gridX(width) and gridY(height)
std::cout << "Please enter the width and height of the grid you want to use." << std::endl;
bool gridIsNotEven = true;
while (gridIsNotEven == true)
{
std::cin >> gridX >> gridY;
if ((gridX*gridY) % 2 == 0)
{
gridIsNotEven = false;
}
else
{
std::cout << std::endl << "The grid produced by these two numbers has an odd number of spaces." << std::endl;
}
}
if (gridX*gridY > 30)
{
std::cout << "This grid is larger than recommended." << std::endl;
}
gridX++;
gridY++;
char gridArray[30][30];
char pairsArray[30][30];
numPairs = ((gridX*gridY) / 2);
//Func : initialiseGrid
initialiseGrid(gridX, gridY, gridArray, pairsArray);
//Func : drawGrid
drawGrid(gridX, gridY, gridArray);
//Func : hidePairs
hidePairs(gridX, gridY, pairsArray, &numPairs);
//Func : findTreasure
findPairs(gridX, gridY, gridArray, pairsArray, &numPairs);
system("Pause");
return 0;
}
void drawGrid(int gridX, int gridY, char gridArray[][30])
{
int printX, printY;
//For(printX = 0, printX < gridX, printX++)
for (printY = 0; printY < gridY; printY++)
{
//For(printY = 0, printY < gridY, printY++)
for (printX = 0; printX < gridX; printX++)
{
std::cout << gridArray[printX][printY] << " ";
}
//END FOR
//Print new line
std::cout << std::endl;
}
//END FOR
}
void hidePairs(int gridX, int gridY, char pairsArray[][30], int *numPairs)
{
int pairsMade, halfPair, curPairX = 0, curPairY = 0;
char pairSymbol = '!';
for (pairsMade = 0; pairsMade < *numPairs; pairsMade++)
{
halfPair = 0;
while (halfPair < 2)
{
curPairX = rand() % gridX;
curPairY = rand() % gridY;
if (pairsArray[curPairX][curPairY] == '?')
{
pairsArray[curPairX][curPairY] = pairSymbol;
halfPair++;
}
}
pairSymbol++;
}
}
void findPairs(int gridX, int gridY, char gridArray[][30], char pairsArray[][30], int *numPairs)
{
int guess1X = 0, guess1Y = 0, guess2X, guess2Y, printChar, pairsFound = 0;
//Display pairs
char pairSymbol = '!';
printChar = 0;
std::cout << std::endl << "The following symbols will be used in the grid:" << std::endl << std::endl;
while (printChar < *numPairs)
{
std::cout << pairSymbol << std::endl;
pairSymbol++;
printChar++;
}
//while ((guessX != treasureX) OR(guessY != treasureY))
while (pairsFound != *numPairs)
{
// User input : guessX and guessY
std::cout << std::endl << "Please enter the co-ordinates of your first guess (e.g. 'X Y')" << std::endl << std::endl;
std::cin.clear();
std::cin >> guess1X >> guess1Y;
gridArray[guess1X][guess1Y] = pairsArray[guess1X][guess1Y];
drawGrid(gridX, gridY, gridArray);
std::cout << std::endl << "Please enter the co-ordinates of your second guess (e.g. 'X Y')" << std::endl << std::endl;
std::cin.clear();
std::cin >> guess2X >> guess2Y;
gridArray[guess2X][guess2Y] = pairsArray[guess2X][guess2Y];
drawGrid(gridX, gridY, gridArray);
if (guess1X > gridX || guess1X < 1 || guess1Y > gridY || guess1Y < 1)
{
std::cout << std::endl << guess1X << ", " << guess1Y << " does not lie inside the grid. Try again." << std::endl;
continue;
}
else if (gridArray[guess1X][guess1Y] == gridArray[guess2X][guess2Y])
{
pairsFound++;
}
else
{
std::cout << std::endl << "Pair not matching" << std::endl << std::endl;
gridArray[guess1X][guess1Y] = '?';
gridArray[guess2X][guess2Y] = '?';
}
// END IF
}
//Print ‘Success! etc.’
std::cout << std::endl << "Success! You found all the pairs!" << std::endl << std::endl;
}
void initialiseGrid(int gridX, int gridY, char gridArray[][30], char pairsArray[][30])
{
int printX, printY;
for (printY = 0; printY < gridY; printY++)
{
for (printX = 0; printX < gridX; printX++)
{
if ((printX == 0))
{
gridArray[0][printY] = printY + '0';
pairsArray[0][printY] = printY + '0';
}
else if ((printY == 0))
{
gridArray[printX][0] = printX + '0';
pairsArray[printX][0] = printX + '0';
}
else
{
gridArray[printX][printY] = '?';
pairsArray[printX][printY] = '?';
}
}
}
}
You initialised the number of pairs to numPairs = gridX * gridY / 2, but that size (gridX, gridY) contains also the header column and row, that do not play a role in the pairing.
So to fix this, your numPairs should be (gridX-1) * (gridY-1) / 2.
Else, the pairs will have been exhausted, but the pairing function is still looking! This is your infinite loop.
I also advise you to find a better name for gridX and gridY to indicate that the headers are counted, or to be very careful in the rest of your code that you understand what gridX and gridY mean and that the grid only starts being an actual thing at index 1 rather than index 0.
It seams it fails only if you add numbers 30 and higher caused by array size
I dont know your settings but ensure you have compiler setting of language standard like GNU C++11
it should work
Turns out there's an infinite loop in the hidePairs function. It's not reading the correct co-ordinates in the pairsArray, so there are spaces it never fills in. And since the loop is only set to end when all unused spaces are filled, it never stops.
Advice for others: always sanity-check your loops!
Related
how to print on the same line inside function, avoid flush
I want to display a progress bar however putting the printing code inside a separate function seems to invoke an std::flush as each time the progress bar is printing in a new line. This did not happen when the code was used inline The code: #include <iostream> #include <unistd.h> void load(int curr, int total) { std::cout << "\n["; int pos = 50 * curr/total; for (int i = 0; i < 50; ++i) { if (i < pos) std::cout << "="; else if (i == pos) std::cout << ">"; else std::cout << " "; } std::cout << "]" << int(float(curr)/(float)total * 100.0) << " %\r"; std::cout.flush(); } int main(){ for( int i = 0; i <= 5; i++ ){ load(i,5); } std::cout << std::endl; return 0; } What it does: [> ]0 % [==========> ]20 % [====================> ]40 % [==============================> ]60 % [========================================> ]80 % [==================================================]100 % What it's supposed to do: print all on the same line
The first line in your function outputs \n, which is what makes it print on a new line every iteration. Fix: #include <iostream> void load(int curr, int total) { std::cout << '['; int pos = 50 * curr/total; for (int i = 0; i < 50; ++i) { if (i < pos) std::cout << '='; else if (i == pos) std::cout << '>'; else std::cout << ' '; } std::cout << ']' << int(float(curr)/(float)total * 100.0) << " %\r" << std::flush; } int main(){ for( int i = 0; i <= 5; i++ ){ load(i, 5); } std::cout << '\n'; }
simplify my code in C++ below
I want to create a program which is able to calculate the surface area, volume, and circumference. for your additional info, I am studying about function, I has just learned about C++ about a week. #include <iostream> #include <string> #include <cmath> using namespace std; int getPostP(string msgP) { int Ppost= 0.000; do { cout << msgP << endl; cin >> Ppost; return Ppost; } while(Ppost<= 0); } int getPostL(string msgL) { int Lpost= 0.000; do { cout << msgL << endl; cin >> Lpost; return Lpost; } while(Lpost<= 0); } int getPostT(string msgT) { int Tpost = 0.000; do { cout << msgT << endl; cin >> Tpost; return Tpost; } while(Tpost <= 0); } int surfaceArea(int Psur, int Lsur, int Tsur) { return (2*Psur*Lsur)+(2*Psur*Tsur)+(2*Lsur*Tsur); } int volume(int Pvol, int Lvol, int Tvol) { return (Pvol*Lvol*Tvol); } float circumference(int Pcir, int Lcir, int Tcir) { return 4*(Pcir+Lcir+Tcir); } int main() { int P = getPostP("enter the P of your block"); int L = getPostL("enter the L of your block"); int T = getPostT("enter the T of your block"); float surfAreaBlock = surfaceArea(P, L, T); float volBlock = volume(P, L, T); float cirBlock = circumference(P, L, T); cout << "block which have P = " << P << " and L = " << L << " and T = "<< T << " have surface area = " << surfAreaBlock << " and volume = " << volBlock << " and cirBlock = " << cirBlock; return 0; } Maybe one of you want to rewrite and add some comment, which parts are able to simplify, so I can understand easier.
First of all, it looks like you should make all of your integer inputs into double instead of int, since it's expected that your inputs won't necessarily be an exact integer amount (probably). Also you can get rid of all of your duplicate functions for entering the parameters. Change it to a single function and call that one for each variable. double getInput(const std::string& prompt) { double input(0.0); do { std::cout << prompt << "\n-> " << std::flush; // forces input to be a double type while (!(std::cin >> input)) { std::cout << "\n-> " << std::flush; std::cin.clear(); std::cin.ignore(256, '\n'); ///< could use streamsize::max here } } while (input <= 0.0); ///< make sure it's positive return input; }
Reading from vectors C++
What is wrong with this code? It detects whether I've reached the coordinates of a monster but only one of them, or the closest one at least. If I travel to other coordinates it doesn't tell me the monster has appeared. Don't know why because I am looping through the monster vector every time I type 'north'. Here is the code. Monster Class: class Monster { public: std::vector<std::string> names; std::vector<double> posx; // North - South std::vector<double> posy; // East - West bool compareCoords(double monsterPosX, double monsterPosY); void cMonster(std::string monsterName, double monsterPosX, double monsterPosY); void randomSpawn(); protected: private: }; compareCoords to detect whether a monster already exists at those coordinates and the cMonster (create monster) functions: void Monster::cMonster(std::string monsterName, double monsterPosX, double monsterPosY) { if (compareCoords(monsterPosX, monsterPosY) == false) { names.push_back(monsterName); posx.push_back(monsterPosX); posy.push_back(monsterPosY); std::cout << "Monster " << monsterName << " has been created at X: " << monsterPosX << " Y: " << monsterPosY << std::endl; } } bool Monster::compareCoords(double monsterPosX, double monsterPosY) { for (unsigned int i = 0; i < posx.size(); i++) { if (monsterPosX == posx[i] && monsterPosY == posy[i]) { return true; } } return false; } Main: int main() { srand(time(0)); Monster newenemy; Character newplayer; newenemy.cMonster("Weezo", 1, 0); newenemy.cMonster("Weezo", 2, 0); newplayer.posx.push_back(0); newplayer.posy.push_back(0); home: std::cout << "-->> "; std::string userInput; std::cin.clear(); getline(std::cin, userInput); if (!userInput.compare("north")) { newplayer.headNorth(); for (unsigned int i = 0; i < newenemy.names.size(); i++) { if (newplayer.posx[i] == newenemy.posx[i] && newplayer.posy[i] == newenemy.posy[i]) { std::cout << "A " << newenemy.names[i] << " has appeared." << std::endl; } } } else if (!userInput.compare("south")) { newplayer.headSouth(); for (unsigned int i = 0; i < newenemy.posx.size(); i++) { if (newplayer.posx[i] == newenemy.posx[i] && newplayer.posy[i] == newenemy.posy[i]) { std::cout << "A " << newenemy.names[i] << " has appeared." << std::endl; } } } else { std::cout << "You have entered an invalid command." << std::endl; } } ^ As you can see here, it shows when I'm at the coordinates of Gorilla but not the second monster, Donald Trump. It just ignores the second one. I've been stuck here for hours, I don't understand what could be wrong. Thank you!
Very stumped on nested void functions with nexted for / if statements
Ok, I've simplified my problem greatly and it is almost perfect except 1 small nagging problem. The function I couldn't figure out how to work I simply turned into its own cpp file for now. I cannot for the life of me understand why this thing is running smooth the first time, but every time after that it takes in 2 lines to work.. #include <iostream> // std::cout #include <iomanip> #include <cstring> #include <locale> // std::locale, std::isdigit, std::isalpha #include <sstream> // std::stringstream #include <cctype> #include <string> #include <limits> void check_row (int row); // Passes int row (row size) from main void check_set (int row); int continue_while_int = 0; int P_row_value; int main() { int row; std::cout<<"Enter an int row "; std::cin >> row; std::cout << std::endl; while (continue_while_int == 0) { check_set(row); } } void check_set(int row) { check_row(row); } void check_row (int row) // 1. clear and ignore incase incorrect input is given. 2. Input string. Checks if empty, "exit" or "Exit", valid length, if input { int row_copy = row; std::string row_length_string; std::string input_length_string; std::stringstream convert_row; // stringstream used for the conversion convert_row << row_copy; //add the value of Number to the characters in the stream row_length_string = convert_row.str(); //set Result to the content of the stream std::string input_Row; std::cout << "enter the P_row "; for (int i = 0; std::cin.clear(),std::cin.ignore(10000,'\n') ; i++) // clears error flags, ignores all input after enter. { std::getline(std::cin, input_Row); // std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); std::string ifempty = input_Row; std::string input_Row_copy = input_Row; // creates copy of input std::stringstream ss_convert_input(input_Row_copy); // gives copy to stringstream instance int input_length = input_Row_copy.length(); // sets an int as input's length // length of input int row_length = row_length_string.length(); // sets and int as length of row int input_as_int; // int to hold input if valid numb string if(ifempty.length() == 0) { std::cout << "error : nothing entered " << std::endl; } else if (input_Row_copy == "exit" || input_Row_copy == "Exit") { std::cout << "Exiting "; continue_while_int = 1; // Exit check_set loop break; } else if (input_length != row_length) // if larger than row_length digits or less than or equal to 0 digits { std::cout << "error : "<< input_Row_copy; std::cout << " is outside row input length "<< std::endl << std::endl; // restar } else if(!(ss_convert_input >> input_as_int)) // restart if unable to convert { std::cout << "error : invalid entry of " << input_Row << std::endl<< std::endl; } else if (input_length == row_length) { if (input_as_int < row && input_as_int >= 0) { P_row_value = input_as_int; std::cout << "Successfully converted string to int. P_row_value = [" << P_row_value << "]" <<"[Column]"; std::cout.width(20); std::cout << " && Input length is " << input_length << std::endl << std::endl; } else { std::cout << "error : " << input_Row_copy << " is not within row boundaries" << std::endl; } } else { std::cout << " error: unknown exception : " << input_Row << std::endl << std::endl; } convert_row.str(std::string() ); convert_row.clear(); // std::cin.ignore(std::cin.rdbuf()->in_avail(),'\n'); } } The output Enter an int row 4 enter the P_row 3 Successfully converted string to int. P_row_value = [3][Column] && Input length is 1 2 2 Successfully converted string to int. P_row_value = [2][Column] && Input length is 1 3 3 Successfully converted string to int. P_row_value = [3][Column] && Input length is 1 1 1 Successfully converted string to int. P_row_value = [1][Column] && Input length is 1 e e error : invalid entry of e r r error : invalid entry of r error : nothing entered
commenting out cout statement causes different (and incorrect) output
I have never experienced anything like this. I was using a cout statement to help me debug a small program, and once I was satisfied with my code I commented out the cout. Now, the code no longer works. Below is the code with the cout commented out. The intent of this program is to test the two hard coded boolean two dimensional arrays for having an odd number of true statements on each row. Thus, the first array should return true and the second array should return false. With the cout statement commented out both instead return false. #include <iostream> using namespace std; template <size_t size_y> bool findEvenDegrees(bool mapArray[][size_y]) { bool returnValue; for (int x=0; x<size_y; x++) { int result = 0; for (int y=0; y<size_y; y++) { result = result + mapArray[x][y]; //the line below causes the problem cout << mapArray[x][y] << "\t" << result << "\t" << x << endl; } if (result%2 == 1) { returnValue = false; break; } } if (returnValue== false) { return returnValue; } else { return true; } } int main() { bool array1[][6] = { {false,true,true,false,false,false}, {true,false,false,true,false,false}, {true,false,false,true,false,false}, {false,true,true,false,true,true}, {false,false,false,true,false,true}, {false,false,false,true,true,false} }; bool array2[][8] = { {false,true,true,false,false,false,false,false}, {true,false,false,true,false,false,false,false}, {true,false,false,true,false,false,false,false}, {false,true,true,false,true,false,false,false}, {false,false,false,true,false,true,true,false}, {false,false,false,false,false,true,false,true}, {false,false,false,false,true,false,false,true}, {false,false,false,false,false,true,true,false} }; bool answer1 = findEvenDegrees(array1); bool answer2 = findEvenDegrees(array2); if (answer1 == true) { cout << "Array 1 has a even degree for every switch." << endl; } else { cout << "Array 1 has a odd degree for at least one switch." << endl; } if (answer2 == true) { cout << "Array 2 has a even degree for every switch."; } else { cout << "Array 2 has a odd degree for at least one switch."; } return 0; }
You never initialize returnValue. If it happens to start out as false it will stay that way and the function will return false.
First, I cleaned up your code a little, and arrived at: #include <iostream> template <size_t S> bool findEvenDegrees(bool (&themap)[S][S]) { for( bool(&row)[S]: themap ) { bool is_degree_odd = false; for( auto col: row ) is_degree_odd ^= col; if( is_degree_odd ) return false; } return true; } int main() { using std::cout; using std::endl; bool array1[6][6] = { {false,true,true,false,false,false}, {true,false,false,true,false,false}, {true,false,false,true,false,false}, {false,true,true,false,true,true}, {false,false,false,true,false,true}, {false,false,false,true,true,false} }; cout << "Array 1 has an " << (findEvenDegrees(array1) ? "even degree for every" : "odd degree for at least one") << " switch." << endl; bool array2[8][8]= { {false,true,true,false,false,false,false,false}, {true,false,false,true,false,false,false,false}, {true,false,false,true,false,false,false,false}, {false,true,true,false,true,false,false,false}, {false,false,false,true,false,true,true,false}, {false,false,false,false,false,true,false,true}, {false,false,false,false,true,false,false,true}, {false,false,false,false,false,true,true,false} }; cout << "Array 2 has an " << (findEvenDegrees(array2) ? "even degree for every" : "odd degree for at least one") << " switch." << endl; return 0; } In the process of cleaning it up, I eliminated the if(result%2 == 1) { resultValue = true; break; }, by effectively returning when I found the first odd-degree row. As I eliminated the resultValue variable, I also killed the "unitialized" bug mentioned by #sth.