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

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;
}

Related

Correctly reading a known number of integer inputs into a vector in C++

I'm new to C++ and wanted to make a small function today which would flip all the elements of an array that was given to it (I had a pretty good idea for it). I started using arrays, but ran into issues since only a pointer to the first element is passed to the function; it was giving some very strange output. It was recommended I use a vector instead, but that started to give me some really odd output, too. I added a cout iterating over the vector values to see what it contains for some sanity-checking, but the outputs are completely bizarre; looks like I'm struggling to work out how to read input into it correctly.
As I mentioned, I first tried an array, which I could read into fine with a range-for loop. I tried that same thing with vectors (solution 1) and found it to be ignoring the first input, and assigning each element the last value that I gave it.
I first tried other Stack overflow threads but I found the solutions far too verbose or not suitable for something as simple as I need.
I thought maybe the vector couldn't be used in the range-for so I did for(auto x : array_size) instead - this gave an error stating there was no suitable "begin" for the function, so I changed this back.
Instead I looked around at the documentation and found .push_back(value) (solution 2) which appeared to put a given value at the end of the vector. Thought I might at least get some input into it correctly, which would be a step in the right direction. Instead, the output seems to show it doubled the number of positions in the vector and just assigned my first input to the furthest position. I imagine this is due to me specifying a size for the vector, and then having push_back grow the vector by that number of inputs (resulting in a double-size vector).
As for the input values themselves, I'm stumped.
Below is the offending bit of code as it stands with solution 2.
int main()
{
int array_size;
auto index_num = 0;
int arr_input = 0;
std::cout << "This program flips an array." << "\n";
std::cout << "Enter how many elements will be in your array: ";
std::cin >> array_size;
std::vector<int> user_array (array_size);
std::cout << "Fill your array with integer values. Press 'Enter' after each: " << std::endl;
for(auto x : user_array)
{
std::cin >> arr_input;
user_array.push_back(arr_input);
}
index_num = sizeof(user_array) / sizeof(user_array[0]); //or just use array_size-1 instead?
std::cout << "Your array, unflipped, contains the values: " << "\n";
for(auto y : user_array)
{
std::cout << "[" << user_array[y] << "] ";
}
Solution 2 provides this output:
Fill your array with integer values. Press 'Enter' after each:
1
2
3
4
5
Your array, unflipped, contains the values:
[0] [0] [0] [0] [0] [0] [0] [0] [0] [1]
Solution 1, where I attempt to input directly into the n-th location of the vector (as I would with an array) provides this output (with the same five 1 - 5 inputs):
Your array, unflipped, contains the values:
[0] [5] [5] [5] [5]
No error messages, everything is perfectly legal, I clearly just don't understand how something simple like a vector is implemented here.
I haven't even got to the taxing bit yet - flipping the array! Any advice appreciated.
std::vector<int> user_array (array_size) creates a vector containing array_size zeros. You then use push_back which adds additional elements to the end. You need to create an empty vector using std::vector<int> user_array, and optionally with a capacity of array_size by calling user_array.reserve(array_size). Since your vector starts out empty now, you'll need to change for(auto x : user_array) to a non-range-based loop such as for (int i = 0; i < array_size; i++).
sizeof(user_array) / sizeof(user_array[0]) only works with plain C arrays, not vectors. Use array_size or user_array.size().
In the last range-based for loop, y is the values in the array, not the indices. So print y, not user_array[y].
You seem to be confusing std::vector with C-style arrays.
std::vector<int> user_array (array_size);
initializes user_array with array_size zeroes.
for(auto x : user_array)
{
std::cin >> arr_input;
user_array.push_back(arr_input);
}
As noticed by Alexander Zhang, this piece modifies the vector while iterating over it, which results in Undefined Behaviour. It could result in anything happeining in your program, including infinite loop, crashing completely, supposingly working correct or demons flying out of your nose
index_num = sizeof(user_array) / sizeof(user_array[0]); //or just use array_size-1 instead?
This line makes no sense. You can get the length of vector using its size() method: user_array.size();, but you don't use that variable anyway.
for(auto y : user_array)
{
std::cout << "[" << user_array[y] << "] ";
}
This loop makes no sense either. y is not an index in the vector, it is a value from that vector. If you have a vector {10, 20, 30}, then in first iteration y is equal to 10, in second iteration y is 20 and in third y is 30.
After fixing the errors, your code should look like this:
std::vector<int> user_array ();
std::cout << "Fill your array with integer values. Press 'Enter' after each: " << std::endl;
for(int i = 0; i < array_size; ++i)
{
std::cin >> arr_input;
user_array.push_back(arr_input);
}
std::cout << "Your array, unflipped, contains the values: " << "\n";
for(auto y : user_array)
{
std::cout << "[" << y << "] ";
}
Or for an (invisible) increase in performance, you can reserve the size of the vector before you read it:
std::vector<int> user_array ();
user_array.reserve(array_size);
std::cout << "Fill your array with integer values. Press 'Enter' after each: " << std::endl;
for(int i = 0; i < array_size; ++i)
{
int x;
std::cin >> x;
user_array.push_back(x);
}

Vector going out of bounds

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.

Output of an expanded array returns unexpected answer

I have finished writing a program that included reversing, expanding and shifting arrays using the pointer requirement asked by the professor. Everything compiles but the answer from the expand function does not return what I wish: adding 0s after the old user input array which asks for the size of the array and the numbers you wish to put into the array. I think my problem may lie from the fact that I include a pointer on something that might not have a reference in the program. Below is my code:
// *numPtr refers to my old user input array and int tamaño is the size of the array
void expandArray(int *numPtr, int tamaño) {
int *nuevoArray = new int[tamaño *2];
for (int i = 0; i<tamaño; i++) {
nuevoArray[i] = numPtr[i];
}
for (int i = tamaño; i < (tamaño*2); i++) {
nuevoArray[i] = 0;
}
std::cout << nuevoArray << " ";
}
As I said, my theory of the code not compiling the way I wish is because I use the *nuevoArray and it has no reference in my main code, but then again, I am just a beginner with C++. I was thinking of just doing a vector, but I think I would not follow the pointer requirements placed by the professor.
If you want to print the contents of nuevoarray, just use a for loop like this:
for (int i = 0; i < (tamaño*2); i++) {
std::cout << nuevoArray[i] << " ";
}
std::cout << "\n";
Also, since you are using new[] to create the array, you should not forget to delete[] it!
you can print your array by using
for (int i = 0 ; i < tamano * 2 ; ++i) {
std::cout << nuevoArray[i] << " ";
}
std::cout << std::endl;
or in c++11
for (auto i : nuevoArray) {
std::cout << i << " ";
}
std::cout << std::endl;
PS: The std::endl will return to the start of the new line and flush the cout buffer.
Your code does appear to be allocating a larger array and correctly copying data from numPtr into the new array and also correctly filling the remainder of the new array with zeros.
You don't explicitly say what you expect this function to output, but I'm guessing you expect it to print out the contents of the new array, and that you believe there's a problem because instead of that, you're seeing it print something like "0x7fb46be05d10".
You're not correctly printing the array out. Instead you're printing the memory address of the first element out. If you want to see the contents, then you need to loop over the elements of the array and print each one out individually.
Here's a function showing one way of doing that:
#include <algorithm>
#include <iterator>
void printArray(int *arr, int n) {
std::copy(arr, arr + n, std::ostream_iterator<int>(std::cout, " "));
}
Now you can replace the line std::cout << nuevoArray << " "; in your existing code with printArray(nuevoArray, tamaño*2);
(Also it sounds like whoever is teaching you C++ should take a look at this presentation from the recent C++ conference, CppCon 2015: Stop Teaching C)

C++ program only lists last value entered into an array

I am trying to output the values present in the array, that are accepted during runtime, onto the console. But when I run this program I get the 5 values in the array as the last value only.
For example: if i give 0 1 2 3 4 as the five values for this program then the output is shown as 4 4 4 4 4.
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int arrsize = 5;
int *ptr = new int[arrsize];
*ptr = 7;
cout << *ptr << endl;
cout << "enter 5 values:";
for (int i = 0; i < arrsize; i++)
{
cin >> *ptr;
cin.get();
}
cout << "the values in the array are:\n ";
for (int i = 0; i < arrsize; i++)
{
cout << *ptr << " ";
}
delete[] ptr;
cin.get();
return 0;
}
Both of your loops:
for (int i = 0; i < arrsize; i++)
...
loop over a variable i that is never used inside the loop. You are always using *ptr which refers always to the first element of the dynamically allocated array. You should use ptr[i] instead.
A part from that, dynamic allocation is an advanced topic. I'd recommend sticking with simpler and more commonly used things first:
std::cout << "Enter values:";
std::vector<int> array(std::istream_iterator<int>(std::cin), {});
std::cout << "\nThe values in the array are:\n";
std::copy(begin(array), end(array), std::ostream_iterator<int>(std::cout, " "));
Live demo
Following issues I think you could tackle:
The first include can be omitted I think. Your code works without that.
You use cin.get(), not sure why you need that. I think you can remove that. Even the one at the very end. You could put a cout << endl for the last newline. I am using Linux.
And use ptr like an array with index: ptr[i] in the loops as mentioned in the other answer. ptr[i] is equivalent to *(ptr+i). You have to offset it, otherwise you're overwriting the same value (that is why you get that result), because ptr points to the first element of the array.
P.S.: It seems that if you're using Windows (or other systems) you need the cin.get() to avoid the console to close down or so. So maybe you'd need to check it. See comments below.

Trying to pass an array to a function and find the sum

I am newbie to programming and I am trying to pass an array into a function and add all the elements together and return the sum. The problem is that I am getting a garbage value for the sum. I have researched on how to pass arrays to functions and I do not know if I'm supposed to use a pointer to pass arrays. I am not good with pointers anyways.
Here is my code
#include <cmath>
#include <cstdlib>
using namespace std;
float mean(int);
int sum(int ARRZO[5]);
int total;
int main()
{
int ARRZ[5];
char *inname = "example.txt";
ifstream infile(inname);
if (!infile) {
cout << "There was a problem opening file " << inname << " for reading." << endl;
return 0;
}
cout << "Opened " << inname << " for reading." << endl;
for(int i=0; i<11; i++)
{
while (infile >> ARRZ[i])
{
cout << "Value from file is " << ARRZ[i] << endl;
}
}
total=sum(ARRZ);
cout<<"the sum of the elements in the array is"<<total<<endl;
system("PAUSE");
return 0;
}
int sum(int ARRZO[])
{
int sumz=0;
for (int i=0; i<5; i++)
{
sumz+=ARRZO[i];
cout<<ARRZO[i];
}
cout<<sumz<<endl;
return sumz;
}
You are actually reading all the values from the file in ARRZ[0] because of the inner loop. By the time you get to i=1, you are at the end of the file, and not reading anything.
Remove one loop, and increment i when you have read successfully a value.
I'm not sure what you think this pair of nested loops is supposed to do:
for(int i=0; i<11; i++)
{
while (infile >> ARRZ[i])
{
cout << "Value from file is " << ARRZ[i] << endl;
}
}
But (as #aliexisdm pointed out) the inner loop reads the entire content of the file. What he didn't (at least directly) point out is that you're reading every one of those values into the first element of your array. Then you're getting back to the outer loop, incrementing i, and trying to read the file again -- but since the stream's failbit has been set, all your subsequent attempts at reading are guaranteed to fail.
After that, you add up the 5 items in the array, but since you haven't read anything into 4 of them (and never initialized its contents) you end up with the last item you read from the file + 4 garbage values, giving still further garbage as the result (well, usually anyway -- you really have undefined behavior, so the program could crash and burn instead, but with most current computers, you'll just get some meaningless number).
I, however, would advise changing the program a bit more than just removing one loop and incrementing in the loop that's left. Instead, I'd remove all the (explicit) loops, and make some attempt at making real use of what the standard library provides.
You can read the numbers from the file in one fell swoop:
std::ifstream infile(inname);
std::vector<int> ARRZ ((std::istream_iterator<int>(infile)),
std::istream_iterator<int>());
Then you can sum them all with std::accumulate:
int sum = std::accumulate(ARRZ.begin(), ARRZ.end(), 0);
Finally, you can print out the result:
cout << "The sum of the elements in the array is: " << sum << "\n";
Since, however, you only read the values from the file to add them together, you don't really need to store them at all. You could just add them together and print out the result:
cout << "The sum of the elements in the file is: "
<< std::accumulate(std::istream_iterator<int>(infile),
std::istream_iterator<int>(), 0);
The whole job reduced to one step...