Stack around the variable ' ' was corrupted - c++

void GameBoard::enterShips()
{
char location[1];
int ships = 0;
int count = 1;
while(ships < NUM_SHIPS)
{
cout << "Enter a location for Ship " << count << ": ";
cin >> location;
cout << endl;
Grid[location[0]][location[1]] = SHIP;
ships++;
count++;
}
}
Im writing a battleship game. I have the board layouts working and the computers randomly generated ships. Now I am working on this method to prompt the user to enter coordinates for the ships When I run the program, it allows me to enter 5 ships. When I enter the 6th ship, it gives me this error.
Stack around the variable location was corrupted.
Ive looked for answers online and have not found anything exclusive.
Any help would be appreciated.

location is an array of a single char.
There is no location[1].

You are prompting the memory address of location array to your user. You should ask location indices separately:
void GameBoard::enterShips()
{
int location[2];
int ships = 0;
int count = 1;
while(ships < NUM_SHIPS)
{
cout << "Enter a location for Ship " << count << ": ";
cin >> location[0];
cin >> location[1];
cout << endl;
Grid[location[0]][location[1]] = SHIP;
ships++;
count++;
}
}
Notice int location[2]; since an array of size 1 can only hold one element. I also changed the element type to int. Reading char's from the console will result in ASCII values, which are probably not what you want.

cin >> location;
location is an array of one char. This can't succeed because when you read from a stream into a char array, a null terminator has to be added (which takes one character). You will inevitably overrun the bounds of the array.
You can use a std::string, which will help you avoid any buffer overrun issues:
std::string location;
if (!(std::cin >> location)) {
// handle input error
}
Note also that you probably need to convert the string representations of the numbers into numeric values. You can easily do this by reading from the stream into two int objects instead:
int x_location, y_location;
if (!(std::cin >> x_location >> y_location)) {
// Handle input error
}
if (x_location >= X_DIMENSION || x_location < 0 ||
y_location >= Y_DIMENSION || y_location < 0) {
// Handle out-of-range error
}
// use x_location and y_location

You made the location variable only able to hold a single character. You access it expecting it to hold at least 2 characters. If you're using cin and expecting to read exactly two characters, a better method would be:
char locationX, locationY;
// ...
std::cin >> locationX >> locationY;
// ...
Grid[locationX][locationY] = SHIP;

Related

Program outputs incorrect numbers from array

Jeopardy point adding code.
The program is supposed to get the number of players with a dynamic array.
From there, you can enter players names and it will insert the names into a two-dimensional array.
Then you can choose to call on a player to start adding points to.
After looping a certain amount of times and pressing 0, the while loop will cease to run and will skip down to the for loop outputting players name and then points.
Problem: If I input "1" for playerNumber, and I start adding points to index [0][1] and outputs numbers quite different from the original numbers I put in. If there are more than 2 players, 2 of the 3 players have random numbers while one remains an accurate point count.
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
//GLOBAL SCOPE, all loops and other boxes can use these
//Declaration variables w cout & cin.
int playerNumber;
string playerNames;
bool flag = true;
cout << "How many players are there: ";
cin >> playerNumber;
cout << endl;
//Array Declaration.
string playerList[playerNumber][2]; //Dynamic array. changes during program runtime.
int points[playerNumber]; //Dynamic array. Changes during runtime
//GLOBAL SCOPE, all loops and other boxes can use these
//Assigning values to arrays now.
cout << "Enter the players names: " << endl;
//Assigns player name to each row.
for(int i = 0; i < playerNumber; i++){
cin >> playerNames;
playerList[i][0] = playerNames; //Assigns players name to the array
cout << "Player " << i + 1 << ": " << playerList[i][0] << endl;
}
while(flag){
//LOCAL VARIABLES
int choice = 0; //Always reverts back to zero to prevent addition error.
int pointsValue = 0; //Always reverts back to zero to prevent addition error.
//LOCAL VARIALES
cout << "Press 0 to end game, if not, enter player number: " << endl;
cin >> choice;
if(choice == 0){ //Exit out of the while loop
flag = false;
}
else if(cin.fail()){
cout << "Not a number. Try again." << endl;
cin.clear();
cin.ignore(256, '\n');
}
else if(choice < 0 || choice > playerNumber){
cout << "Choice is less than 0 or greater than player count. Try again." << endl;
}
else{
cout << "Enter points: " << endl;
cin >> pointsValue;
cout << endl;
points[choice - 1] += pointsValue; //Assigns points to points array
playerList[choice - 1][1] = (to_string(points[choice - 1])); //Assigns points to playerNumber.
}
}
cout << endl;
cout << "END OF JEOPARDY. HERE ARE THE POINTS!!!" << endl;
cout << endl;
//Current points for each player
//Shows their name and points
for(int i = 0; i < playerNumber; i++){ //Loops so that player name and points are displayed
string playerName = playerList[i][0];
string totalPoints = playerList[i][1];
cout << playerName << " points: " << totalPoints << endl;
}
return 0;
}
Technically, this is illegal:
string playerList[playerNumber][2];
int points[playerNumber];
The size of the array must be known at compile time (not runtime). Though some compilers allow this as an extension to the language, it is not part of the standard language.
Better choice would have been to use std::vector.
Lets assume your compiler allows this:
The next issue is that you don't initialize the values in the array.
int points[playerNumber]; // This is an array of random numbers.
// Sure if you are doing a debug build the
// compiler may be nice and just set all the
// values to zero as speed is not important
// during debugging. But on a release build
// these could be any value.
Also if we want to be technical its actually undefined behavior to read from the array unless you first write a value. Though usally this is not going to cause the program to crash on most architectures and unfortuantely the code just runs like nothing bad is happening.
You can normall initialize the array like this:
int points[10] = {0}; // but your variable size stuff
// will stop working for that.
-------
// so you will have to manually initialize the members
int points[playerNumber];
for(int loop = 0; loop < playerNumber; ++loop) {
points[loop] = 0;
}
Or if you upgrade to vector:
std::vector<int> points(playerNumber,0); // Size and initial value.
// Though you don't need the
// initial value as vector will
// zero init members.
The last issue I will mention is that you are not consistent on checking if the read worked.
cin >> pointsValue;
What do you think happens to pointsValue if the read fails (ie. the user puts in an illegal value). The proper way to check the user input is to put the read inside an if statement.
if ( std::cin >> pointValue) {
// The read worked `pointsValue` has valid user input
}
else {
// The read faild.
// We don't know what the user input should be
}
The other thing to think about is that user input is line based. They add values hit return. So it is a good tactic to exploit that and read user input by the line. Once you have the line parse that and validate input. That way the standard input stream does not go into a bad state.
std::string line;
if (std::get(std::cin, line)) {
// We have a line of user input.
std::stringstream lineStream(std::move(line));
line.clear();
int choice;
if (lineStream >> choice) {
// We have a valid choice from the user.
// or do we. If the user entered `2x` is that valid input?
// because `choice` is 2; but there is still `x` on the
// input stream.
// That's a choice for you as the developer to make.
// if you don't care, then you have valid input. If you do
// care then you need to check there is no bad data on
// the line.
}
else {
// invalid choice
}
}
else {
// The user input stream just ended.
// This could mean the user entered the end-of-stream character
// or if the user had connected some other stream to the
// standard input on the command line and there is no more
// data to read.
}
I would note that this will probably never work for invalid input.
if(choice == 0){ //Exit out of the while loop
flag = false;
}
else if(cin.fail()){
// If you failed to read data from the std::cin
// the the value of `choice` is probably zero
// (if I remember my standard correctly) so the
// first branch of the if tree will be entered
// and you will never enter this branch.
cout << "Not a number. Try again." << endl;
cin.clear();
cin.ignore(256, '\n');
}

how to store data into dynamic array

I have this program that asks user to enter a number and ask the user if they want to view input history. So i was wondering if my code is correct. I want to know if doing cin>>num[count-1] is correct or is there a correct way to get the data the user inputs. Here it is:
#include<iostream>
using namespace std;
int main(){
const int size = 20;
int *num = new int[size];
char answer;
int count = 1;
while(true){
cout<<"ENTER NUMBER: \n";
cin>>num[count-1];
cout<<"TRY AGAIN? ";
cin>>answer;
switch(answer){
case 'y':
count++;
system("cls");
break;
default:
cout<<"INPUT HISTORY: \n";
for(int i=0;i<=count-1;i++){
cout<<num[i]<<endl;
}
count++;
}
}
delete [] num;
return 0;
}
I want to know is doing cin>>num[count-1]` is correct or is there a correct way to get the data the user inputs.
Your code is a c-style code. You have the std::array and std::vector to help you to write a more secure and clean code. Because your tag in your question is dynamic-arrays I suggest to use the std::vector.
Bellow you can check out your code could be with the replacement.
#include <iostream>
#include <vector>
using namespace std;
int main() {
//int *num = new int[size]; //normally you don't need to use new. Let the c++ manage it for you
vector<int> num;
char answer;
while (true) {
cout << "ENTER NUMBER: \n";
num.emplace_back(); //Create a new element to vector num
cin >> num.back(); //set this new element
cout << "TRY AGAIN? ";
cin >> answer;
if (answer == 'y')
system("cls");
else {
cout<<"INPUT HISTORY: \n";
for (auto& numEle : num) //It will interate over all elements of num
cout<< numEle <<endl;
//break; //Maybe you want to break the loop here
}
}
// delete [] num;
return 0;
}
I will first show you the problems in your code. I put in comments.
Then I will explain you, why your input is wrong. Also the answer from user TheArquitect is wrong and will finally lead to a memory overflow.
Your program will also have a desastrous result.
First see the code:
#include<iostream>
using namespace std; // In C++ we never use this statement. Why? See:
// You will find at least 1000 comments in Stackoverflow
int main() {
const int size = 20; // In C++ we use constexpr for compile time constants
int* num = new int[size]; // In C++ we
// Do not use raw pointers for owned memory
// Do not use new
// Do Not use C-Style arrays
// Generally: std::vector should be used
// Or at least std::unique_ptr and std::make_unique
// Also, this 2 lines are nonesense. It is the same as int num[20];
char answer; // All variables should always be initialized
// Variables should be in the scope, where they are necessary
int count = 1; // YOu could use uniform initialization
// Arrays start with index 0 in C++ (also in C )
while (true) { // You are creating an endless loop with desastrous effect
cout << "ENTER NUMBER: \n";
cin >> num[count - 1]; // No, this will not work. Explanation in text
cout << "TRY AGAIN? ";
cin >> answer; // No, this will not work. Explanation in text
switch (answer) { // Switch with only one case can always be expressed with if elese
case 'y':
count++;
system("cls"); // This is a non portable solution
break;
default:
cout << "INPUT HISTORY: \n";
for (int i = 0; i <= count - 1; i++) { // Nearly Never use <= in for loops
// Use for (int i = 0; i < count; i++)
// Do use ++i insted of i++
cout << num[i] << endl;
}
count++;
} // This is an endless loop. count will always be increased. If greater than 20
// then the memory will be corrupted. This will happen always
}
delete[] num; // Dead code. Will never be invoked
return 0;
}
OK. Now, besides the major bugs and the killing out of bounds problem, here the explanation for the problem with inputting data.
Rule: You must always check, if the input operation worked. For that you can check the state of the stream. Additionally, if you do not consume the input data (because of an erronous input by the user), this data is still in the input buffer. And in the next loop it will be read again (without waiting for new user input). The status of the input stream may still be wrong and it will also not read because of this.
Then the endless loop starts to run without user input and corrupts your memory.
You may check, by simply inputting a letter instead of a number.
How to fix?
Again, you must check the state of the stream after reading. This is usually done in the form:
if (std::cin >> number)
Why does this work? Because: The inserter operator returns a reference to the stream (so std::cin) and the boolean '!' not-operator for the std::istream is overwritten. It will show, if the state of the stream is still ok or not.
OK, understood. Now. What to do in case of error? 2 operations:
Clear all failure bits in the state of the stream --> std::cin.clear()
Eat up everything that is still in the input buffer --> std::cin.ignore()
You could write:
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
I assume that you are learing C++ in a class and learn about new and delete. As said, you should not use it. But because teacher request this often in the classes, I will show you now a better solution than yours, still using new, but without (most of) the problems.
#include<iostream>
#include <limits>
int main() {
// We want to create a dynamic array with 20 elements
constexpr size_t MaxArraySize{ 20U };
// Allocate a dynamic arry on the heap
int* numberArray = new int[MaxArraySize];
// Read maximum 20 numbers into our dynamic array
for (size_t currentArrayIndex{}; currentArrayIndex < MaxArraySize; ) {
// Inform the user that he should ent now a number
std::cout << "Enter number: \n";
// Read the number and check, if this worked
if (std::cin >> numberArray[currentArrayIndex]) {
// Now ask, if the user wants to continue or stop
std::cout << "Doy you want to enter more numbers? ('y' or 'n'): ";
// Define variable answer and get user input and check, if ok
if (char answer{}; std::cin >> answer) {
// Does the user want to continue?
if ('y' == answer) {
// Yes, continue. Increment array index
++currentArrayIndex;
}
else {
// No, the user does not want to continue. Show the values entered so far
std::cout << "Input History:\n";
for (size_t i{}; i <= currentArrayIndex; ++i) { // NOTE: <= becuase index has not yet been incrementet
std::cout << numberArray[i] << "\n";
}
break; // Stop the for loop and end the program
}
}
else {
// Strange, input of a character did not work. Should not happen. Terminate program
std::cerr << "\n*** Error: Problem with input!\n\n";
break; // Stop the for loop and end the program
}
}
else {
// The user entered someting wrong, or the input did not work for any other reason
// Inform user about problem
std::cerr << "\n*** Error: No number could be read!\n\n";
// Clear error flag and comsume whatever is in the input buffer
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
// Release dynamic allocated memory
delete[] numberArray;
return 0;
}

Transversing an Array of structs error in C++

Current code:
const int MAX_CODENAME = 25;
const int MAX_SPOTS = 5;
struct Team {
string TeamName[MAX_CODENAME];
short int totalLeagueGames;
short int leagueWins;
short int leagueLoses;
};
//GLOBAL VARIABLES:
Team league[MAX_SPOTS];
void addTeams(){
int i = 0; //first loop
int j; //second loop
while(i < MAX_SPOTS){
cout << "****** ADD TEAMS ******" << endl;
cout << "Enter the teams name " << endl;
scanf("%s", league[i].TeamName) ;
}
void searchTeam(){
string decider[MAX_CODENAME];
cout << "Please enter the team name you would like the program to retrieve: " << endl;
cin >> decider[MAX_CODENAME];
for(int i = 0; i < MAX_SPOTS; i++){
if(decider == league[i].TeamName){
cout << endl;
cout << league[i].TeamName << endl;
break;
}else{
cout << "Searching...." << endl;
}
}
}
I really dont know why its not working but I have included all the perquisite header files such as and but the program crashes when i enter the data and then attempt to search. I get the circle of death and then program not responding then says Process returned 255 (0xFF) . It does not even out put Searching.... the program practically gives up as soon as I enter that name.
Also if this can be optimized by the use of pointers that would be great.
tl;dr run-time error causing the search to fail as soon as i type in a name. And for the record I have checked to make sure the name I entered is valid.
scanf doesn't know about std::string. Use std::cin >> league[i].TeamName.
scanf("%s", league[i].TeamName) ;
This should be changed to
std::cin >> league[i].TeamName ;
A couple of other things here....
string decider[MAX_CODENAME];
cout << "Please enter the team name you would like the program to retrieve: " << endl;
cin >> decider[MAX_CODENAME];
Every time you input a value, you are telling the computer to hold the inputted value at decider[25] but the computer only reads indexes 0-24.
if(decider == league[i].TeamName){
Which array slot are you comparing the team name to? If its the 25th element than the statement should be
if(decider[24] == league[i].TeamName){
Pointers are better suited if the number of TeamNames are unknown. Based on the limited code presented, I highly recommend you stay within the realm of basic data types. For the purposes of troubleshooting, please post your full code in the future.
Your TeamName member variable:
string TeamName[MAX_CODENAME];
is an array of 25 strings, so in this line:
scanf("%s", league[i].TeamName) ;
you are courrupting the array. You don't really want an array anyways, so change the TeamName declaration to:
string TeamName;
and then when you read the name, you'll need to use iostreams which knows how to populate a string type (scanf only works with c char arrays):
std::cin >> league[i].TeamName

do loop statement is causing an infinite loop

I am writing a library program that displays a menu of options letting the user add new books to the library, but in my add statement it accepts the title and then gets caught in an infinite loop. I wrote a book class that mainly uses pointers to assign things, if I need to post that I will. But when you run the program it compiles, displays the menu, and when you choose add a book it accepts the title but as soon as you hit enter it starts an a infinite loop.
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
int main()
{
int bookCounter = 0;
Book library[25];
int menuOption = 0;
char tempt[50] = "\0";
char tempauth[50] = "\0";
char search[50] = "\0";
unsigned int tempp = 0;
do
{
menuOption = 0;
cout << endl << "1. Show the Library" << endl;
cout << "2. Add a Book" << endl;
cout << "3. Search the Library by Title" << endl;
cout << "4. Exit Library" << endl;
cout << "Select a menu option (e.g. 1, 2, etc.): ";
cin >> menuOption;
if(menuOption == 1)
{
for(int i = 0; i < bookCounter; i++)
{
library[i].displayBook();
}
}
else if(menuOption == 2)
{
cout << "Enter the Title: ";
cin >> tempt[50];
cout << endl << "Enter the Author's name: " ;
cin >> tempauth[50];
cout << endl << "How many pages does the book have? (just enter a number, e.g. 675, 300): ";
cin >> tempp;
library[bookCounter].setAuthor(tempauth);
library[bookCounter].setTitle(tempt);
library[bookCounter].setPages(tempp);
bookCounter++;
menuOption = 0;
}
else if(menuOption == 3)
{
cout << "Enter a title you would like search for (will return partial matches): ";
cin >> search[50];
for (int i = 0; i < bookCounter; i++)
{
int temp = strcmp(search, library[i].getTitle());
if (temp == 1)
{
library[i].displayBook();
}
}
}
}while(menuOption != 4);
system("pause");
return 0;
}
The problem is caused by the way you are trying to read into the arrays:
cin >> tempt[50];
This tries to read a single character into the character at index 50 of the array tempt, which is outside the bounds of the array (which has valid indices in the range [0,49]).
This means only the first character of the entered title will be consumed from the output. Similarly for author. Hence, only the first two characters which you have entered are actually read. Then, this line will be encountered:
cin >> menuOption;
Here, what is left in the buffer (the remainder of the title) will be read, expecting a number. As this does not match a valid format for a number, you will get an error flag in cin. This will mean that all resulting inputs will also fail, menuOption will never change and your program gets stuck in a loop.
A solution to your problem would be to read into tempt without index. You can also check if a read has failed using if(cin.fail()) which should only trigger if there's been an error. If so, handle it and then call cin.clear() to reset the error flags.
I think that this line cause the problem,
cin >> search[50];
You're accessing out bound of search array.
One error is when you type in the menu option, the 'return' stays in the input buffer. The next read of char[] in your tempt variable, will be skipped.
Type cin.ignore(); after cin >> menuOption;
Also, you should read tempt instead instead of tempt[50].
This
cin >> tempt[50];
accesses a non-existent entry in the array. You probably meant to code
cin >> tempt;
Or, better, use std::string instead of raw char array.

Stack around the variable is corrupted

I have what seems like a pretty simple, beginner question that I must be missing something obvious. I am just trying to prompt the user to input a 4 digit number and then take in the input as an array, splitting up the digits to be by themselves. I thought it hade something to do with "cin >> input[4]" I just can't seem to get the right answer.
int main()
{
int input[4]; //number entered by user
cout << "Please enter a combination to try for, or 0 for a random value: " << endl;
cin >> input[4];
}
When I go to run it, I get an error message "Stack around the variable was corrupted.
I tried looking at similar examples in other questions but I just can't seem to get it right. I need the input as one 4 digit number and then split it up to a 4 position array.
If anyone could help I would greatly appreciate it.
Your array is of size 4, so elements have indicies 0 .. 3; input[4] is located behind the end of your array so you are attemping to modify memory not allocated or allocated for other stuff.
This will work for you:
cin >> input[0];
cin >> input[1];
cin >> input[2];
cin >> input[3];
You do not need an arry to input 4 digit number.
int in;
int input[4];
cin >> in;
if(in>9999 || in < 1000) {
out << "specify 4 digit number" << endl;
return;
}
input[0] = in%1000;
input[1] = (in-1000*input[0])%100;
input[2] = (in-1000*input[0]-100*input[1])%10;
input[3] = in-1000*input[0]-100*input[1]-input[2]*10;
The problem is that you are trying to read in a character that does not exist (the one at index 4).If you declare input as int input[4];, then it doesn't have any characters at index 4; only indices 0...3 are valid.
Perhaps you should just use an std::string and std::getline(), and you could then parse the user input to integers however you like. Or you can try
std::cin >> input[0] >> input[1] >> input[2] >> input[3];
if you can live with the constraint that the numbers must be whitespace-separated.
This includes a small bit of error checking:
int n = 0;
while( n < 1000 || n >= 10000 ) // check read integer fits desired criteria
{
cout << "enter 4 digit number: ";
cin >> n; // read the input as one integer (likely 10 digit support)
if( !cin.good() ) // check for problems reading the int
cin.clear(); // fix cin to make it useable again
while(cin.get() != '\n'); // make sure entire entered line is read
}
int arr[4]; // holder for desired "broken up" integer
for( int i=0, place=1; i<4; ++i, place *= 10 )
arr[i] = (n / place) % 10; // get n's place for each slot in array.
cout << arr[3] << " " << arr[2] << " " << arr[1] << " " << arr[0] << endl;