Let's look at a simple example to illustrate vectors and a few of the member functions.
#include<iostream>
#include<vector>
using namespace std;
int main()
{
// vectors are parameterized types
vector <double> junk1(10); // allocate 10 double elements, initialize all to 0.0
vector <int> junk2(10, 7); // allocate 10 int elements, initialize all to 7
vector <int> grades; // no size specified; contains zero elements
int num_students, i;
cout << "Size of junk1 is " << junk1.size() << ".\n";
cout << "Size of junk2 is " << junk2.size() << ".\n";
cout << "Size of grades is " << grades.size() << ".\n" << endl;
cout << "How many students are in CS 102? ";
cin >> num_students;
// set the size at run time with member function resize()
grades.resize(num_students);
cout << "Size of grades is " << grades.size() << ".\n" << endl;
// fill vector grades, use [] to access individual elements
for(i = 0; i < num_students; i++) {
cout << "enter grade for student number " << i+1 << ": ";
cin >> grades[i];
}
// resize vector at run time; new size can be constant, expr., or variable
grades.resize(1000);
cout << endl << "Size of grades is " << grades.size() << ".\n";
grades.resize(num_students + 1);
cout << "Size of grades is " << grades.size() << ".\n";
grades.resize(grades[2]);
cout << "Size of grades is " << grades.size() << ".\n";
// different example; declare new vectors; *** DON'T DO THIS***
vector <int> test1 (80, -1); // initialize 80 elements to to -1
vector <int> test2 (85); // automatically set 85 elements to 0
vector <int> count (101); // automatically set 101 elements to 0
vector <double> average (101); // automatically set 101 elements to 0.0
// assign values in vector test1 to vector test2; truncate test2 to 80 elements
test2 = test1;
cout << "\nsize of test2: " << test2.size() << endl;
// assign values in count to test2; expand test2 to 101 elements
test2 = count;
cout << "\nsize of test2: " << test2.size() << endl << endl;
// Are the two vectors equal in size and element-by-element value?
if(test1 != test2) cout << "\nVectors are not equal.\n\n";
// Member function at() returns a reference in the vector and is safer than the [] operator
// because at() won't let you reference items outside the bounds of the vector.
// Example: It is safer to use test1.at(i) than it is to use test1[i].
// Example: use at member function to check array boundary - does test1[1000] exist?
// If not, abort with runtime error
test1.at(1000) = 200;
cout << "We will never reach this point if there is no test1[1000].\n";
return 0;
}
|
OUTPUT:
Size of junk1 is 10.
Size of junk2 is 10.
Size of grades is 0.
How many students are in CS 102? 5
Size of grades is 5.
enter grade for student number 1: 100
enter grade for student number 2: 96
enter grade for student number 3: 82
enter grade for student number 4: 75
enter grade for student number 5: 90
Size of grades is 1000.
Size of grades is 6.
Size of grades is 82.
size of test2: 80
size of test2: 101
Vectors are not equal.
terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check
zsh: abort a.out
|
#include<iostream>
#include<vector>
using namespace std;
void func(int a[], vector <int> v)
{
int i;
v[2] = a[0] + v[1];
a[2] = v[2] % a[1];
v[0] = v[2] / a[1];
cout << "In func(): \n";
for(i = 0; i < 3; i++)   cout << a[i] << " ";
cout << endl;
for(i = 0; i < 3; i++)   cout << v[i] << " ";
cout << endl << endl;
}
int main(void)
{
int a[3] = {10, 11, 12};
vector |
Output: Size of vector: 3 In func(): 10 11 9 2 21 31 In main(): 10 11 9 20 21 22 |
#include <iostream>
#include <vector>
using namespace std;
vector <int> change_and_return(vector <int> v)
{
int i;
for (i = 0; i < a.size(); i++) v[i] = 30 + i;
return v;
}
int main()
{
vector <int> v1(10), v2;
int i;
for (i = 0; i < v1.size(); i++) v1[i] = 10+i;
v2 = change_and_return(v1);
for (i = 0; i < v1.size(); i++) {
cout << "i: " << i << " - v1[" << i << "]: " << v1[i] <<
" - v2[" << i << "]: " << v2[i] << endl;
}
}
|
When you run it, you'll see that change_and_return() changes the contents of v1, but that its version of v1 is a copy of the version in main(). So the version of v1 in main() remains unchanged when we print it out. Note also that when we return a vector, it makes a copy. So this program actually has three copies of 10-element vectors -- the original v1 in main, the copy of v1 in change_and_return(), and the return value that is put into v2.
UNIX> g++ -o pex9 pex9.cpp UNIX> pex9 i: 0 - v1[0]: 10 - v2[0]: 30 i: 1 - v1[1]: 11 - v2[1]: 31 i: 2 - v1[2]: 12 - v2[2]: 32 i: 3 - v1[3]: 13 - v2[3]: 33 i: 4 - v1[4]: 14 - v2[4]: 34 i: 5 - v1[5]: 15 - v2[5]: 35 i: 6 - v1[6]: 16 - v2[6]: 36 i: 7 - v1[7]: 17 - v2[7]: 37 i: 8 - v1[8]: 18 - v2[8]: 38 i: 9 - v1[9]: 19 - v2[9]: 39 UNIX>
This makes vectors convenient, because you can return them from procedures and you don't have to worry about overwriting stuff. However, it can be inefficient time-wise -- making copies of large vectors will consume time.
Now, look at the array version of the above code. In: pexA.cpp:
#include <iostream>
using namespace std;
int *change_and_return(int *a)
{
int i;
for (i = 0; i < 10; i++) a[i] = 30 + i;
return a;
}
int main()
{
int a[10], *b;
int i;
for (i = 0; i < 10; i++) a[i] = 10+i;
b = change_and_return(a);
for (i = 0; i < 10; i++) {
cout << "i: " << i << " - a[" << i << "]: " << a[i] <<
" - b[" << i << "]: " << b[i] << endl;
}
}
|
When you run it, you'll see that change_and_return() actually changes a in main(). That's because there is only one copy of the array -- the procedure call and return value simply pass around pointers:
UNIX> g++ -o pexA pexA.cpp UNIX> pexA i: 0 - a[0]: 30 - b[0]: 30 i: 1 - a[1]: 31 - b[1]: 31 i: 2 - a[2]: 32 - b[2]: 32 i: 3 - a[3]: 33 - b[3]: 33 i: 4 - a[4]: 34 - b[4]: 34 i: 5 - a[5]: 35 - b[5]: 35 i: 6 - a[6]: 36 - b[6]: 36 i: 7 - a[7]: 37 - b[7]: 37 i: 8 - a[8]: 38 - b[8]: 38 i: 9 - a[9]: 39 - b[9]: 39 UNIX> UNIX>
#include <iostream>
using namespace std;
int *initialize_array()
{
int a[10];
int *a_ptr;
int i;
for (i = 0; i < 10; i++) a[i] = 30+i;
a_ptr = a;
return a_ptr;
}
int main()
{
int *a;
int i;
a = initialize_array();
for (i = 0; i < 10; i++) {
cout << "i: " << i << " - a[" << i << "]: " << a[i] << endl;
}
}
|
What it does is have
Well, because the memory for a in
initialize_array() only exists while
initialize_array() is running. When
initialize_array() returns, the memory is freed up to be reused.
And it does get reused in the cout statement.
This is a disastrous bug because it is hard to track down.
Remember it, because it will happen to you someday.
The vector version of this code works fine -
pexC.cpp:
This works fine because a copy of v is made and returned
to main().
UNIX> g++ -o pexB pexB.cpp
UNIX> pexB
i: 0 - a[0]: 30
i: 1 - a[1]: 10
i: 2 - a[2]: 1
i: 3 - a[3]: 11597
i: 4 - a[4]: -1599039200
i: 5 - a[5]: -1599040224
i: 6 - a[6]: -1073744104
i: 7 - a[7]: -1867372625
i: 8 - a[8]: -1610605544
i: 9 - a[9]: 10
UNIX>
#include <iostream>
#include <vector>
using namespace std;
vector <int> initialize_array()
{
vector <int> v(10);
int i;
for (i = 0; i < 10; i++) v[i] = 30+i;
return v;
}
int main()
{
vector <int> v;
int i;
v = initialize_array();
for (i = 0; i < 10; i++) {
cout << "i: " << i << " - v[" << i << "]: " << v[i] << endl;
}
}
UNIX> g++ -o pexC pexC.cpp
UNIX> pexC
i: 0 - v[0]: 30
i: 1 - v[1]: 31
i: 2 - v[2]: 32
i: 3 - v[3]: 33
i: 4 - v[4]: 34
i: 5 - v[5]: 35
i: 6 - v[6]: 36
i: 7 - v[7]: 37
i: 8 - v[8]: 38
i: 9 - v[9]: 39
UNIX>