STL vector: resize() and assign() - c++

Having a class members std::vector<double> v and int n, what is the difference between using the following on this vector, which is not initialized:
v.assign(n, 0.0);
or
v.resize(n, 0.0);

assign sets the size to n and all element values to 0.0, whereas resize sets the size to n and only new element values to 0.0.
If v is empty beforehand, they're the same, but assign is probably clearer.

I guess by not initialized, you mean it's default initialized, i.e, an empty vector, then
v.assign(n, 0.0);
and
v.resize(n, 0.0);
both changes the size of the vector to n and all the elements to 0.0. Note that for non-empty vectors, they are usually not the same, resize() only sets the new elements to 0.0.

Assign means replacing a vector with new properties (size and elements). Resize means holding old data and expanding the new vector with new elements, this in case the new size is greater than the old one, otherwise shrink the size and eliminate the extra.
Run the following code twice. One for assign the second one for resize (just uncomment the first one).
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> vec1;
vec1.assign(7,100);
// vec1.resize(7, 100);
std::cout << "Size: " << vec1.size() << std::endl;
for (unsigned int i(0); i < vec1.size(); ++i)
{
std::cout << vec1[i] << std::endl;
}
vec1.resize(4,5);
// vec1.assign(4,5);
std::cout << "\nSize: " << vec1.size() << std::endl;
for (unsigned int i(0); i < vec1.size(); ++i)
{
std::cout << vec1[i] << std::endl;
}
vec1.resize(10,5);
// vec1.assign(10,5);
std::cout << "\nSize: " << vec1.size() << std::endl;
for (unsigned int i(0); i < vec1.size(); ++i)
{
std::cout << vec1[i] << std::endl;
}
std::cin.get();
return 0;
}

Related

Why my C++ program can't get me the value which I have assigned before instead of random double?

I have been working on a project which handles Matrices and make operations with it. I'm doing it to learn memory management and understand object-oriented programming. So, first, I don't want to use a matrix library.
In my class, I made a constructor for Matrix class which has three parameters: int row_number, int column_number, string inside_expression. inside_expression is a way to create matrix and assign values in it. Using template of inside_expression is looks like MatLab but without handling spaces:
Ex. maths::Matrix matrix1(3, 3, "1,5.7,6;23,4,0;5,5,2;");
It doesn't need to be square matrix by the way. maths is the name of namespace.
So, for now, everything works perfectly. Program makes a poly-dimensional array with doubles and after it did, it gave the console a looking of matrix for debugging purposes. I was testing the code for every possible givens and I saw a mistaken output. If last element of last column and last row on a matrix is zero, it assigns _matrix[last_row][last_col] = 0 but after assignment, if I want to print the value it gives me a random double.
Why it makes that? I'll copy my constructor function down here. Thank you for all. :) Have a nice day.
Matrix::Matrix(int _row, int _column, std::string _inside) {
//std::cout << _inside << "\n";
row = _row - 1;
col = _column - 1;
// Matrix Creation with Arrays
_matrix = new double*[row];
for (int index = 0; index <= row; index++) {
_matrix[index] = new double[col];
}
/* Template for creating matrix: "1,5.4,6,7;8.7,9,7,3;15,4,7,2;"
Because of that we need to find their positions on string
and store them as two dimensional array.
[first; , sec; , third;]
[1, [8.7, [15,
5.4, 9, 4,
6, 7, 7,
7] 3] 2]
*/
int row_cursor = 0; // For row value.
while (true) {
int pos = _inside.find(";");
//std::cout << "\tpos: " << pos << "\n";
// If there's no ; character, it'll break the while loop.
if (pos == std::string::npos) {
if (row_cursor == 0) {std::cerr << "Given matrix is invalid type!";}
break;
}
// Finding commas and inserting numbers to matrix.
for (int index = 0; index <= col; index++) {
int item_pos = _inside.substr(0, pos).find(",");
//std::cout << "\t\titem_pos: " << item_pos << "\n";
// If can't find comma (when x;y,z,f; situation happens)
if (item_pos == -1 || item_pos >= pos) {
int _OLD_POS = pos;
pos = _inside.find(";");
//std::cout << "\t\tnew pos: " << pos << "\n";
_matrix[row_cursor][index] = std::stod(_inside.substr(0, pos));
//std::cout << "\t\tmsubstr val: " << _inside.substr(0, pos) << "\t";
//std::cout << "matix value: " << _matrix[row_cursor][index] << "\n";
_inside.erase(0, pos + 1);
//std::cout << "\t\terased _inside: " << _inside << "\n";
pos = _OLD_POS - _inside.substr(0, pos).length();
//std::cout << "\t-> pos: " << pos << "\n";
} else {
_matrix[row_cursor][index] = std::stod(_inside.substr(0, item_pos));
//std::cout << "\t\tmsubstr val: " << _inside.substr(0, item_pos) << "\t";
_inside.erase(0, item_pos + 1);
//std::cout << "\t\terased _inside: " << _inside << "\n";
pos = pos - _inside.substr(0, item_pos).length();
//std::cout << "\t-> pos: " << pos << "\n";
}
}
row_cursor++;
}
// To see matrix:
for (int index = 0; index <= row; index++) {
for (int jindex = 0; jindex <= col; jindex++) {
std::cout << _matrix[index][jindex] << " ";
}
std::cout << "\n";
}
Note about code: I commentted the console prints to not disturb you.
The last valid index into an array with row elements is row-1. Here you create an array with row elements and the last iteration of the loop tries to access _matrix[row] but that is not part of the array.
_matrix = new double*[row];
for (int index = 0; index <= row; index++) {
_matrix[index] = new double[col];
}
Accessing an array out-of-bounds invokes undefined behavior. Executing your code, anything or nothing can happen.
Common convention is to use 0-based indexing and half open intervals, ie your loop should be
for (size_t index = 0; index < row; ++index)
// ^----------------- !!!
PS: Using 0-based or 1-based indexing each has pros and cons. The important thing about a convention is not that it has no alternatives that are as valid, but that you apply it consistently. Don't mix 0 and 1-based indexing. It will be a mess.

garbage values for vector push_back

I'm trying to assign an array's values to a vector. It seems to be working fine for one vector, but when I do it for a second, I'm getting back garbage values. I cout the number and I know it's correct, but it's not assigning correctly. I don't understand because it's working fine for the first vector.
int sorted[] = {0,1,2,3,4,5,6,7,8,9,10};
// make two smaller arrays, do this untill they are a base case size;
void split(int *dataIN, int dataSize){
// new data will be broken up into two vectors with each half of the
// original array. These will be size firstHalfSize and secondHalfSize.
int firstHalfSize;
int secondHalfSize;
vector<int> firstHalf;
vector<int> secondHalf;
// test to see if array in is odd or even
bool isOdd;
if (dataSize%2 == 1){
isOdd = true;
}else if (dataSize%2 == 0){
isOdd = false;
}
// determine length of new vectors
// second half is firstHalf + 1 if odd.
firstHalfSize = dataSize/2;
if (isOdd){
secondHalfSize = firstHalfSize + 1;
}else if (!isOdd){
secondHalfSize = firstHalfSize;
}
// assign first half of dataIn[] to firstHalf vector
cout << "firs: " << firstHalfSize << endl;
for (int i = 0; i < firstHalfSize; i++){
cout << "a: " << dataIN[i] << endl;// make sure i have the right number
firstHalf.push_back(dataIN[i]);// assign
cout << "v: " << firstHalf[i] << endl;// make sure assigned correctly
}
// do the same for second half
cout << "second: " << secondHalfSize << endl;
for (int i = firstHalfSize; i < (firstHalfSize+secondHalfSize); i++){
cout << "a: " << dataIN[i] << endl;
secondHalf.push_back(dataIN[i]);
cout << "v: " << secondHalf[i] << endl;
}
}
int main(void){
split(sorted, sizeof(sorted)/sizeof(int));
return 0;
}
This is my result. As you can see the first vector push_back went fine and the array values (after "a: ") are also correct.
firs: 5
a: 0
v: 0
a: 1
v: 1
a: 2
v: 2
a: 3
v: 3
a: 4
v: 4
second: 6
a: 5
v: -805306368
a: 6
v: 2
a: 7
v: -805306368
a: 8
v: 0
a: 9
v: 0
a: 10
v: 0
In the second case, you are indexing from firstHalfSize.
You need to cout the values starting from index 0. For example:
cout << "v: " << secondHalf[i-firstHalfSize] << endl;
You are iterating firstHalf from 0 to firstHalfSize with the variable i, so i will be within the range of firstHalf, when you use operator[] - in the second vector's case, i does not mean the same thing.
The filling of the vector is working. It is just your debug output that is incorrect. When outputting values from secondHalf you need to use indexes from 0, not from firstHalfSize.
You can write your code more simply if you take advantage of the std::vector range constructor that takes a pair of iterators. Array pointers can be treated as iterators:
void print(const std::vector<int>& data){
for(int value : data)
std::cout << value << " ";
std::cout << "\n";
}
void split(int *dataIN, int dataSize){
auto firstHalfSize = (dataSize + 1) / 2;
std::vector<int> firstHalf(dataIN, dataIN + firstHalfSize);
std::vector<int> secondHalf(dataIN + firstHalfSize, dataIN + dataSize);
std::cout << "firstHalf: ";
print(firstHalf);
std::cout << "seconHalf: ";
print(secondHalf);
}
Live demo

Do (c++) vectors shrink after elements are removed?

Vectors double their size each time they run out of space when adding an element, but what about when you remove elements? say you added 800 elements to an array, and on the addition of that 800th element, the vector doubles its size to be able to hold 1600 elements. Now what if you start taking away elements to the point that its only holding say 5 or 10 elements?
will it recognize that the vector is much smaller than half the size of the space reserved for future elements and reserve less space?
Vectors do not decrease in capacity when removing elements! This is to allow future elements to be added efficiently into the existing buffer.
If it has already allocated a block of memory, it will continue to use it because it would be inefficient for it to free up some memory and later find it has to allocate more memory.
I always recommend writing a test snippet of code to test these sorts of things.
For example, I threw this together in 2 minutes to verify that I was telling you correct information:
#include <iostream>
#include <vector>
void printInfo(std::vector<char> &_vector)
{
std::cout << "Size: " << _vector.size() << std::endl;
std::cout << "Capacity: " << _vector.capacity() << std::endl;
std::cout << std::endl;
}
int main()
{
int numbElems = 10;
std::vector<char> myvector;
std::cout << "Nothing entered" << std::endl;
printInfo(myvector);
for (int i = 0; i < 10; i++) {
for (int c = 0; c < numbElems; c++) {
myvector.push_back(i);
}
std::cout << "Pushed " << numbElems << std::endl;
printInfo(myvector);
}
for (int i = 0; i < 5; i++) {
for (int c = 0; c < numbElems; c++) {
myvector.pop_back();
}
std::cout << "Popped " << numbElems << std::endl;
printInfo(myvector);
}
myvector.erase(myvector.begin(), myvector.end());
printInfo(myvector);
std::cout << "max_size: " << myvector.max_size() << std::endl;
return 0;
}
If you compile and run you will see Capacity never goes down in size. Even after erase, or some of the elements are removed.
On linux you can use less to scroll through the output.

c++: swapping vectors and pointer invalidation?

I seem to be having a problem with swapping the elements of two vectors. I have two vectors, x and y that hold objects of type myclass. The myclass has only one public member w. I create a vector of pointers pointing to the members w of x and then swap the vectors x and y. I would expect the vector of pointers to still point to the w members of x but this does not seem to be the case.
Here is a trivial example to reproduce my problem.
#include <iostream>
#include <vector>
using namespace std;
struct myclass
{
double w;
};
int main()
{
vector<myclass> x(10);
for(int i=0; i!=10; i++) x[i].w = i;
for(auto el : x) std::cout << el.w << std::endl; /* prints i */
std::cout << std::endl;
vector<double *> px(10);
for(int i=0; i!=10; i++) px[i] = &x[i].w;
for(auto el : px) std::cout << *el << std::endl; /* prints i */
std::cout << std::endl;
vector<myclass> y(10);
for(int i=0; i!=10; i++) y[i].w = 2*i;
for(auto el : y) std::cout << el.w << std::endl; /* prints 2*i */
std::cout << std::endl;
y.swap(x);
for(auto &el : x) std::cout << &el.w << " " << el.w << std::endl; /* prints 2*i as it should */
std::cout << std::endl;
for(auto &el : px) std::cout << el << " " << *el << std::endl; /* should print 2*i, but prints i */
std::cout << std::endl;
}
Notice that x and y have swapped elements but px stills points to the old elements. I read that using swap is not supposed to invalidate pointers/iterators. Is this correct or am I missing something?
Thanks in advance!
The pointers and iterators are not invalidated, but they follow the contents of the container.
The contents of x are swapped into y, but iterators and pointers to these values will keep pointing at them (even though they are now in y).
Think about it, how could it work in any other way? If two containers of unequal length were swapped, what would pointers to elements near the end of the longer container point to in the shorter container? How would it be possible to implement swap() in O(1) if the elements of each container had to be moved in memory to ensure that pointers remained valid?

How can I change the value of the elements in a vector?

I have this code, which reads in input from a file and stores it in a vector. So far, I've gotten it to give me the sum of the values within the vector and give the mean of the values using the sum.
What I'd like to do now is learn how to access the vector again and subtract a value from each element of the vector and then print it out again. For example, once the sum and mean are calculated, I'd like to be able to reprint each value in the terminal minus the mean. Any suggestions/examples?
#include <iostream>
#include <vector>
#include <fstream>
#include <cmath>
using namespace std;
int main()
{
fstream input;
input.open("input.txt");
double d;
vector<double> v;
cout << "The values in the file input.txt are: " << endl;
while (input >> d)
{
cout << d << endl;
v.push_back(d);
}
double total = 0.0;
double mean = 0.0;
double sub = 0.0;
for (int i = 0; i < v.size(); i++)
{
total += v[i];
mean = total / v.size();
sub = v[i] -= mean;
}
cout << "The sum of the values is: " << total << endl;
cout << "The mean value is: " << mean << endl;
cout << sub << endl;
}
You can simply access it like an array i.e. v[i] = v[i] - some_num;
Well, you could always run a transform over the vector:
std::transform(v.begin(), v.end(), v.begin(), [mean](int i) -> int { return i - mean; });
You could always also devise an iterator adapter that returns the result of an operation applied to the dereference of its component iterator when it's dereferenced. Then you could just copy the vector to the output stream:
std::copy(adapter(v.begin(), [mean](int i) -> { return i - mean; }), v.end(), std::ostream_iterator<int>(cout, "\n"));
Or, you could use a for loop...but that's kind of boring.
You can access the values in a vector just as you access any other array.
for (int i = 0; i < v.size(); i++)
{
v[i] -= 1;
}
Your code works fine. When I ran it I got the output:
The values in the file input.txt are:
1
2
3
4
5
6
7
8
9
10
The sum of the values is: 55
The mean value is: 5.5
But it could still be improved.
You are iterating over the vector using indexes. This is not the "STL Way" -- you should be using iterators, to wit:
typedef vector<double> doubles;
for( doubles::const_iterator it = v.begin(), it_end = v.end(); it != it_end; ++it )
{
total += *it;
mean = total / v.size();
}
This is better for a number of reasons discussed here and elsewhere, but here are two main reasons:
Every container provides the iterator concept. Not every container provides random-access (eg, indexed access).
You can generalize your iteration code.
Point number 2 brings up another way you can improve your code. Another thing about your code that isn't very STL-ish is the use of a hand-written loop. <algorithm>s were designed for this purpose, and the best code is the code you never write. You can use a loop to compute the total and mean of the vector, through the use of an accumulator:
#include <numeric>
#include <functional>
struct my_totals : public std::binary_function<my_totals, double, my_totals>
{
my_totals() : total_(0), count_(0) {};
my_totals operator+(double v) const
{
my_totals ret = *this;
ret.total_ += v;
++ret.count_;
return ret;
}
double mean() const { return total_/count_; }
double total_;
unsigned count_;
};
...and then:
my_totals ttls = std::accumulate(v.begin(), v.end(), my_totals());
cout << "The sum of the values is: " << ttls.total_ << endl;
cout << "The mean value is: " << ttls.mean() << endl;
EDIT:
If you have the benefit of a C++0x-compliant compiler, this can be made even simpler using std::for_each (within #include <algorithm>) and a lambda expression:
double total = 0;
for_each( v.begin(), v.end(), [&total](double v) { total += v; });
cout << "The sum of the values is: " << total << endl;
cout << "The mean value is: " << total/v.size() << endl;
Just use:
for (int i = 0; i < v.size(); i++)
{
v[i] -= valueToSubstract;
}
Or its equivalent (and more readable?):
for (int i = 0; i < v.size(); i++)
v[i] = v[i] - valueToSubstract;
You might want to consider using some algorithms instead:
// read in the data:
std::copy(std::istream_iterator<double>(input),
std::istream_iterator<double>(),
std::back_inserter(v));
sum = std::accumulate(v.begin(), v.end(), 0);
average = sum / v.size();
You can modify the values with std::transform, though until we get lambda expressions (C++0x) it may be more trouble than it's worth:
class difference {
double base;
public:
difference(double b) : base(b) {}
double operator()(double v) { return v-base; }
};
std::transform(v.begin(), v.end(), v.begin(), difference(average));
int main() {
using namespace std;
fstream input ("input.txt");
if (!input) return 1;
vector<double> v;
for (double d; input >> d;) {
v.push_back(d);
}
if (v.empty()) return 1;
double total = std::accumulate(v.begin(), v.end(), 0.0);
double mean = total / v.size();
cout << "The values in the file input.txt are:\n";
for (vector<double>::const_iterator x = v.begin(); x != v.end(); ++x) {
cout << *x << '\n';
}
cout << "The sum of the values is: " << total << '\n';
cout << "The mean value is: " << mean << '\n';
cout << "After subtracting the mean, The values are:\n";
for (vector<double>::const_iterator x = v.begin(); x != v.end(); ++x) {
cout << *x - mean << '\n'; // outputs without changing
*x -= mean; // changes the values in the vector
}
return 0;
}