Vector going out of bounds - c++

I'm attempting to iterate through a list of 6 'Chess' pieces. Each round they move a random amount and if they land on another then they 'kill' it.
The problem is that when the last piece in my vector kills another piece I'm getting a vector 'out of range' error. I'm guessing it's because I'm iterating through a vector whilst also removing items from it, but I'm not increasing the count when I erase a piece so I'm not entirely sure. Any help would be greatly appreciated.
Here is my vector:
vector<Piece*> pieces;
pieces.push_back(&b);
pieces.push_back(&r);
pieces.push_back(&q);
pieces.push_back(&b2);
pieces.push_back(&r2);
pieces.push_back(&q2);
and this is the loop I iterate using:
while (pieces.size() > 1) {
cout << "-------------- Round " << round << " --------------" << endl;
round++;
cout << pieces.size() << " pieces left" << endl;
i = 0;
while (i < pieces.size()) {
pieces.at(i)->move(board.getMaxLength());
j = 0;
while (j < pieces.size()) {
if (pieces.at(i) != pieces.at(j) && col.detectCollision(pieces.at(i), pieces.at(j))) {
cout << pieces.at(i)->getName() << " has slain " << pieces.at(j)->getName() << endl << endl;
pieces.at(i)->setKills(pieces.at(i)->getKills() + 1);
pieces.erase(pieces.begin() + j);
}
else {
j++;
}
}
i++;
}
}
Solution
pieces.erase(pieces.begin() + j);
break;

Your logic needs a little refinement.
The way you coded it, it seems the "turn based" nature of chess has been replaced by a kind of "priority list" -- the pieces closer to the start of the vector are allowed to move first and, thus, get the priority into smashing other pieces.
I don't know if you want this logic to be right or wrong. Anyway, the trouble seems to be due to unconditionally executing the line
i++;
It should not be executed if you remove a piece for the same reason 'j++' isn't executed: you will jump over a piece.

I have a very strong feeling that this line of code:
i++;
is your culprit which is missing either a needed break condition or another conditional check that is missing from your loops. As it pertains to your nested while loops' conditions since they are based on the current size of your vector and are not being updated accordingly.
while (pieces.size() > 1) {
// ...
while (i < pieces.size()) {
// ...
while (j < pieces.size()) {
// ...
}
}
}
This is due to the fact that you are calling this within the inner most nested loop:
pieces.erase(pieces.begin() + j);
You are inside of a nested while loop and if a certain condition is met you are then erasing the object at this index location within your vector while you are still inside of the inner while loop that you never break from or check to see if the index is still valid.
Initially you are entering this while loop with a vector that has 6 entries, and you call erase on it within the nested loop and now your vector has 5 entries.
This can reek havoc on your loops because your index counters i & j were set according to the original length of your vector with a size of 6, but now the vector has been reduced to a size of 5 while you are still within the inner most nested loop that you never break from nor check to see if the indices are valid. On the next iteration these values are now invalidated as you never break out of the loops to reset the indices according to the new size of your vector, nor check to see if they are valid.
Try running this simple program that will demonstrate what I mean by the indices being invalidated within your nested loops.
int main() {
std::vector<std::string> words{ "please", "erase", "me" };
std::cout << "Original Size: " << words.size() << '\n';
for (auto& s : words)
std::cout << s << " ";
std::cout << '\n';
words.erase(words.begin() + 2);
std::cout << "New Size: " << words.size() << '\n';
for (auto& s : words)
std::cout << s << " ";
std::cout << '\n';
return 0;
}
-Output-
Original Size: 3
please erase me
New Size: 2
please erase

You should save locally pieces.at(i) and use this local variable everywhere you use pieces.at(i).
To avoid both elements out of bound and logical problems you can use std::list.
As aside, you should use std::vector<Piece*> only if these are non-owning pointers, otherwise you should use smart-pointers, probably unique_ptr.

Related

Can't figure out this stack output c++

So I have a stack example I created following a tutorial using the stack library
stack<string> custs;
custs.push("george");
custs.push("louie");
custs.push("florence");
// cout << "size" << custs.size() << endl;
if (!custs.empty()) {
for (int i = 0; i <= custs.size(); i++) {
cout << custs.top() << endl;
custs.pop();
}
}
I ran this and got the output:
florence
louie
My question is why isn't it outputting George as well? The program outputs the top data then pops it. This means it should output Gorge then pop it after. Why doesn't this happen? initially the code was i < cust.size so I thought because i is not less than 1 it would not ouput. So I switched it to <= and it still doesn't output George. How come?
It is because you are both increasing i and reducing the size of the stack in the loop.
You can rewrite your loop like this:
while (!custs.empty()) {
cout << custs.top() << endl;
custs.pop()
}
Here is a step by step explanation of what is happening so you can understand it better:
First, i starts as 0, and custs.size() returns 3. Since 0 <= 3 is true, the body of the loop executes, printing "florence" and removing it from the stack.
On the second iteration, i equals 1, and custs.size() returns 2, because you had 3 items but you removed one. Since 1 <= 2 is true, the body of the loop executes again, printing "louie" and removing it from the stack.
Then, i equals 2, and custs.size() returns 1, because you already removed 2 elements. Since 2 <= 1 is false, the body of the loop doesn't execute, and the loop ends.
As you can see, the problem is that your loop's condition changes on each iteration. There are a couple of ways to fix this:
int s = custs.size();
for (int i = 0; i < s; i++) {
cout << custs.top() << endl;
custs.pop();
}
By doing that, you store the original size of the stack, so you can iterate without problems.
Another solution would be to check if the stack is empty on each iteration with a while loop:
while (!custs.empty()) {
cout << custs.top() << endl;
custs.pop();
}
By doing that, you check if there are any elements left to print each time.
Hope this helps!
When you use for loop like this
for (int i = 0; i <= custs.size(); i++) {
cout << custs.top() << endl;
custs.pop();
}
it loops directly till the size of stack which decreases in each iteration.
which in my opinion is the main reason your code is not working. I rewrite this as
int z = custs.size() ;
for(int i=0;i<=z;i++)
{
cout<<custs.top()<<endl;
custs.pop();
}
and it worked perfectly fine. In my opinion, the best approach is to use while loop like this
while(!custs.empty())
{
cout<<custs.top()<<endl;
custs.pop();
}

why after pop_back() operation it still prints the complete vector?

I have the following main program that creates a Stack object, fills it with integers and then pops them. The code files fine, but the pop_back() part does not seem to work, even after pop_back() it prints all values. How is this possible?
#include<iostream>
#include<vector>
using namespace std;
int main(){
vector<int> myVector; //initalization
int value;
//input in a vector using push_back
for (int i = 0; i < 6;i++){
cin >> value;
myVector.push_back(value);
}
cout<<"Initial vector size:" << myVector.size() <<endl;
for (int i = 0; i < 6;i++){
cout << myVector[i];
}
cout << endl;
myVector.pop_back();
cout<<"Vector size after pop back: " << myVector.size() << endl;
cout << endl;
cout << "First element is: " << myVector.front() << endl;
cout << "Last element is : " << myVector.back() << endl;
for (int i = 0; i < 6;i++){
cout << myVector[i];
}
return 0;
}
Everyone has focused on saying this is undefined behavior fix code, but question was why it works.
To understand why it works you must understand how vector works more or less.
Vector allocates some block of memory to store items.
size of this block is defined by capacity, which says how many items can be stored in vector, without allocating new block of memory
capacity is usually bigger then size of the vector
now when you remove items form vector, capacity and allocated block of memory doesn't change. This is an optimization.
when you remove item from back just destructor is called (for int it does nothing) and size of vector is reduced.
your value is not cleared just marked as out of vector size
so when you use operator[] it doesn't check if you exceed its size. It just returns value at specific adders
since pop_back just reduced size you value is still there
Note if you call shrink_to_fit after pop_back there is a great chance it will and with crash or you will not receive same value. Still this is undefined behavior and anything can happen.
Another way to see your code is bad is to use at which checks if index is in valid range.
std::vector::pop_back function works just fine. After you perform a call to it, you try to print all 6 values instead of 5. Therefore, you are accessing invalid memory. In your case, program prints out the value that was removed but in some other case it could print some garbage value. That's why this is UB - Undefined Behavior.
Try the following and you will see that last element is not in the std::vector:
for (int i = 0; i < myVector.size(); i++) {
std::cout << myVector[i];
}
or, even better, use range-based for loop:
for (auto const i : myVector) {
std::cout << i;
}
The problem is in the way you loop through the vector - you are expecting it to have 6 elements even after you have removed the last element. This is undefined behavior.
Using a range based for would be preferred in both cases where you want to output the contents of the vector:
for (auto i:myVector) {
cout << i;
}

i'm having trouble with a while-loop that I just can't figure out why it won't work as desired

Made a while-loop and I'm not getting the result I think I should be getting.
I've done a little debugging and got nothing. Visual Studio 2019 is saying I'm good to go.
int main()
{
double num_enter;
vector<double> nums(0);
while (cin >> num_enter)
{
nums.push_back(num_enter);
sort(nums.begin(), nums.end());
if (num_enter < nums.front())
{
cout << num_enter << " is the smallest one yet.\n" << endl;
}
else if (num_enter > nums.back())
{
cout << num_enter << " is the biggest one yet.\n" << endl;
}
return 0;
}
I want a while(cin>>enter_num) loop to read num_enter and do a vector.push_back(num_enter) followed by the vector sort function and have it out put if the number has been "the smallest yet" or "the biggest yet" but its not working. could you point out what I'm doing wrong? I'm new be gental.
There is only one number in the vector. None of the conditions are met, if you enter one, one is not greater than one or less than one, hence it is not printing anything because you are not handling that case. Add an else block that prints if the numbers are equal then hopefully it will be clear to you why that is happening.
try this
// Example program
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
double num_enter;
vector<double> nums(0);
while (cin >> num_enter) {
nums.push_back(num_enter);
//sort(nums.begin(), nums.end());
// Lets say you entered 1
// 1 < 1 -> false
if (num_enter < nums.front())
{
cout << num_enter << " is the smallest one yet.\n" << endl;
}
// 1 > 1 -> false
else if (num_enter > nums.back())
{
cout << num_enter << " is the biggest one yet.\n" << endl;
}
else // 1 == 1
{
cout << "Numbers are equal" << endl;
}
return 0;
}
}
Syntax of vector:
vector vectorName(size);
vector nums(0)
In your code nums is a vector of size zero.
Vector is a dynamic array.
Array of zero size is meaningless.
Check this link to see different ways of declaring vector.
suppose you code order should be changed, the if-elseif-else block should be put in front of the push_back and sort,
or if you really want to maintain the order, if-elseif-else should be corrected like if(num_enter == nums.front()) ... else if(num_enter == nums.back())... else,
only then you can know if your input number has been the biggest or smallest yet.
And initialize like vector<double>nums(0) is little weird, just using vector<double>nums is fine

Finding the end of an array in a loop in C++?

I wanted to distinguish between the end of an array an the rest of the elements (in a for loop), but most examples initializes a variable outside the loop, which I think clutters the loop. The shortest example I have achieved is by looking at pointer addresses in a ranged-based for-loop:
for(auto& x : arr){
cout << x;
if(&x != &*end(arr)-1)
cout << ", ";
}
This doesn't need an extra variable, but I am not 100% sure of the implications from using pointers in C++.
A more (or less?) readable example where I initialize a variable in the for-statement, in a way that looks quite intuitive (edit doesn't give portability to fuctions):
for(int i{0}, len{sizeof(arr)/sizeof(*arr)}; i<l; i++){
cout << arr[i];
if(i!=len-1)
cout << ", ";
}
Is there a more readable/better/shorter way to do this without extra includes?
Are there any cons to these approaches?
Why not do the following?
bool not_first_item = false;
for(auto x : arr){
if (not_first_item) {
cout << ", ";
not_first_item = true;
}
cout << x;
}
It will print a comma before each item except the first one. It will get the result you require without the need of using complicated pointers.
If all you have is a pointer to an element in an array, there is no portable way of detecting the position of that element in an array.
Alternatives; best first:
Use a std::vector. That has similar semantics as a plain old array and has the benefit of carrying in the size.
Pass the size of the array as an additional parameter, with size_t type.
Use a magic value to signify the end of an array.
Note that using &x is pointless as x is a value copy. Consider auto& x instead?
This might help
l=sizeof(arr)
for(int i{0}; i<l-1; i++){
cout << arr[i];
cout << ", ";
}
cout << arr[sizeof(arr)];
or
for(int i{0}; i<sizeof(arr)-1; i++){
cout << arr[i];
cout << ", ";
}
cout << arr[sizeof(arr)];
there is no extra condition.
If showing is the main intention
A concise way that I like, without extra branch:
const char* sep = "";
for (const auto& x : arr) {
std::cout << sep << x;
sep = ", ";
}
Yes it uses extra variable.
As a general rule, you should not discard information that you need. When you use a range-based for loop you abstract away the position of an element in the container (and in fact the form of the container). Therefore, it is not the most appropriate tool for the job. You could do this with an index or an iterator because those hold enough information for you to tell whether the element you are iterating over is the last one.
The standard library offers two helpful functions begin and end that either call the member functions begin and end of STL containers, or pointers to the first and past-the-end elements for C-style arrays. Because of the way the end condition is checked, you don't need anything more than a forward iterator.
assert(std::begin(arr) != std::end(arr));
for (auto it = std::begin(arr); it + 1 != std::end(arr); ++it) {
std::cout << *it << ", ";
}
std::cout << *(std::end(arr) - 1) << '\n';
The above code is fine if you know that you're never going to attempt to print an empty container. Otherwise, you'll need an extra if statement to check for that. Note that even if you have a random access iterator and you use the condition it < std::end(arr) - 1 you might reason that it's fine even for empty arrays, but it is undefined behavior and it might lead to some unexpected bugs when optimizations are turned on.
Not 100% sure what I was looking for but I think that the real answer might be to check for the starting item like #ed_heel proposed, but I really only needed to change what I checked for in the range-based for-loop to make it much neater:
for(auto &x : arr)
{
cout << (&x == arr ? "" : ", ") << x;
}
works since arr is an array (a.k.a. pointer in disguise).

c++ vector not updating in nested for loop

So I create and initialize a vector (of size nmask+3) to 0, and I assign an initial value to one of the elements. I then make a for loop that goes through the first nmask elements of the vector and assigns to each element an average of 26 other elements in the vector (defined by the 4D int array voxt, which contains vector addresses).
My problem is that when I check the values of nonzero elements in my vector (phi) within the nested loop (the first cout), the values are fine and what I expect. However, when the loop finishes going through all nmask elements (for (int i= 0; i<nmask; i++) exits), I check the nonzero elements of phi again, and they are all lost (reset to 0) except for the last non-zero element (and element tvox which is manually set to 1).
I feel that since phi is initialized outside of all the loops, there should be no resetting of values going on, and that any updated elements within the nested loop should remain updated upon exit of the loop. Any ideas as to what is going on / how to fix this? Code is below; I tried to comment in a sense of the outputs I'm getting. Thanks in advance.
vector<double> phi(nmask+3, 0); //vector with nmask+3 elements all set to 0 (nmask = 13622)
phi[tvox]= 1; //tvox is predefined address (7666)
for (int n= 0; n<1; n++)
{
vector<double> tempPhi(phi); //copy phi to tempPhi
for (int i= 0; i<nmask; i++)
{
for (int a= -1; a<=1; a++)
{
for (int b= -1; b<=1; b++)
{
for (int c= -1; c<=1; c++)
{
if (!(a==0 && b==0 && c==0))
{
//oneD26 is just (double) 1/26
phi[i]= tempPhi[i]+oneD26*tempPhi[voxt[i][1+a][1+b][1+c]];
if (phi[i]!=0)
{
//this gives expected results: 27 nonzero elements (including tvox)
cout << n << " " << i << " " << a << b << c << " " << phi[i] << endl;
}
}
}
}
}
}
phi[svox]= 0; //svox = 7681
phi[tvox]= 1;
for (int q= 0; q<nmask; q++)
{
//this gives only 2 nonzero values: phi[tvox] and phi[9642], which was the last nonzero value from 1st cout
if (phi[q]!=0)
cout << q << " " << phi[q] << endl;
}
}
Difficult to tell just what is going on, but the easiest explanation is that after phi[i] gets set to non-zero and displayed to cout, it gets set to zero again in one of the later iterations through the inner loops.
If you do some tracing and check phi[i] just before updating you'll see that you often overwrite a non-zero element with zero.
Note: I have no idea what your code does, this is pure Sherlock Holmes reasoning.. if after the loops you find only 2 non-zero elements then the only logical consequence is that after updating something to non-zero later in the loop you update it to zero.
phi[i]= tempPhi[i]+oneD26*tempPhi[voxt[i][1+a][1+b][1+c]];
The nested for-loops using a, b, and c run for a combined 9 iterations with the same value of i. Since you overwrite phi[i] to a new value every time, you only retain the value from the last iteration where a, and c are all 1. If that last iteration happens to produce zero values, then phi[i] will have lots of zeroes. Perhaps you meant to do something like phi[i] += ... instead of phi[i] = ...?
I do suggest to replace the meat of the loop with something like
const boost::irange domain(-1,2);
for (int i: boost::irange(0, nmask)) for (int a: domain) for (int b: domain) for (int c: domain)
{
if (a==0 && b==0 && c==0)
continue;
//oneD26 is just (double) 1/26
phi[i]= tempPhi[i]+oneD26*tempPhi[voxt[i][1+a][1+b][1+c]];
if (phi[i]!=0)
{
//this gives expected results: 27 nonzero elements (including tvox)
cout << n << " " << i << " " << a << b << c << " " << phi[i] << endl;
}
}
Of course, for brevity I assume both boost/range.hpp and c++0x compiler. However, with trivial macro's you can achieve the same. That is without writing/using a proper combinations algorithm (why is that not in the standard, anyway).