The functions all have a similar signature. Here's the declaration for
quicksort
:
void quicksort(vector<int> &data, int low_idx, int high_idx);
The header file signatures call for vector
objects to contain data,
and it uses the &
modifier to the parameters to make them reference
parameters. These are explained in turn:
vector
is a standard C++ class. A vector
is essentially an
intelligent list data structure, with methods that let you append,
insert, remove, push, pop, and query its data at valid indices.
Consider: vector<int> data;
This means data
is a vector
that contains int
elements. This additional syntax is necessary,
because otherwise the compiler doesn't know what kind of elements will
be in the data structure.
Hints with vectors:
vector<int> data; // declares an empty vector that holds ints, named data
data.push_back(4); // append 4 to end of data. now contains [ 4 ]
data.push_back(6); // append 6 to end of data. now contains [ 4, 6 ]
data.push_back(2); // append 2 to end of data. now contains [ 4, 6, 2 ]
int n = data.size(); // can address data[0] through data[n-1], but not data[n]
// make a sub-vector using data[0] through data[mid-1], but not data[mid].
vector<int> left = vector<int>(data.begin(), data.begin() + mid);
Reference documentation for vector
.
The parameter data
is passed by reference. This means that
whatever changes you make to the variable inside the function will be
visible in the calling context.
Say there are functions:
void vegas(int val) {
val = 1234;
}
void change_me(int& val) {
val = 1234;
}
... and we do the following:
int x = 4;
int y = 5;
vegas(x);
change_me(y);
cout << x << " " << y << endl;
It prints 4 1234
. Whatever happens in vegas
stays in
vegas. Whatever happens in change_me
is persistent outside.
// This is a complete code example that demonstrates various forms of
// function parameters.
//
// 1. pointers: pass a copy of the address of a variable to a
// function. input pointer is copied to a separate stack variable that
// is available for use in the function. dereferencing that pointer
// gives direct access to the original memory.
//
// 2. value: pass a copy of the value of a variable to a
// function. nothing that function can do can modify that variable's
// value in the calling context. unless it is a pointer.
//
// 3. reference: use the exact memory from the calling context in the
// function. this essentially just gives a new name to the same
// memory. any modifications to that memory will persist after the
// function exits.
//
// 4. constant reference: same as plain old reference, except the
// compiler will trigger an error if it can determine that you are
// modifying the parameter.
//
// This program outputs something like the following:
//
// main A: val: 1, address: 0x7fff513f457c
// pointer: val: 0x7fff513f457c, *val: 1, address: 0x7fff513f4528
// main B: val: 2, address: 0x7fff513f457c
// reference: val: 2, address: 0x7fff513f457c
// main C: val: 3, address: 0x7fff513f457c
// value: val: 3, address: 0x7fff513f452c
// main D: val: 3, address: 0x7fff513f457c
//
// Notice that of all the memory addresses printed out, there are only
// two; the one ending in 7c is the memory address of `val` at the top
// of `main`, the one ending in 28 is the address of a pointer, and
// that pointer's value is the 7c address that everything else refers
// to.
#include <iostream>
using namespace std;
void point(int* val);
void value(int val);
void ref(int& val);
void vegas(const int& val);
int main() {
int val = 1;
cout << "main A: val: " << val << ", address: " << &val << endl;
point(&val);
cout << "main B: val: " << val << ", address: " << &val << endl;
ref(val);
cout << "main C: val: " << val << ", address: " << &val << endl;
value(val);
cout << "main D: val: " << val << ", address: " << &val << endl;
}
void point(int* val) {
cout << "pointer: val: " << val << ", *val: " << *val << ", address: " << &val << endl;
*val = 2;
}
void ref(int& val) {
cout << "reference: val: " << val << ", address: " << &val << endl;
val = 3;
}
void value(int val) {
cout << "value: val: " << val << ", address: " << &val << endl;
val = 4;
}
void vegas(const int& val) {
cout << "const: val: " << val << ", address: " << &val << endl;
// val = 5; // will not compile because val is const, so it is commented out
}
Passing vectors by reference works exactly the same way:
void change_vec(vector<int>& stuff) {
stuff.push_back(99);
}
...
vector<int> foo;
change_vec(foo);
cout << foo.size() << endl; // 1
cout << foo[0] << endl; // 99
For more on this C++ feature see introduction to parameter passing modes.
This is also informative: https://www.ibm.com/support/knowledgecenter/SS4QVT_8.5.1/com.ibm.xlcpp111.aix.doc/language_ref/cplr233.html