You have an array, and you want to traverse (walk through) it.
int a[] = {31, 41, 59, 26, 53, 58}; for (int i=0; i!=6; ++i) cout << a[i];
314159265358
a[i]
is the same as *(a+i)
.
i<6
, rather than i!=6
.
i++
rather than ++i
.
Let’s do it with a pointer:
int a[] = {31, 41, 59, 26, 53, 58}; for (int *p = &a[0]; p != &a[6]; ++p) cout << *p;
314159265358
a[i]
(addition+indirection) we have just indirection.
vector
traversalYou can traverse a vector
in the same way:
vector<int> a = {31, 41, 59, 26, 53, 58}; for (int *p = &a[0]; p != &a[6]; ++p) cout << *p;
314159265358
or, avoiding the magic number 6:
vector<int> a = {31, 41, 59, 26, 53, 58}; for (int *p = &a[0]; p != &a[a.size()]; ++p) cout << *p;
314159265358
vector<int> a = {31, 41, 59, 26, 53, 58}; for (vector<int>::iterator it = a.begin(); it != a.end(); ++it) cout << *it;
314159265358
iterator
is a type provided by the templated vector
class.
int *
, might not
*
works on it
++
works on it
.begin()
to it
.end()
auto
is your friendThis is prettier:
vector<int> a = {31, 41, 59, 26, 53, 58}; for (auto it = a.begin(); it != a.end(); ++it) cout << *it;
314159265358
for
loopThis is exactly the same:
vector<int> a = {31, 41, 59, 26, 53, 58}; for (auto v : a) cout << v;
314159265358
The for
loop is defined to use .begin()
and .end()
,
just as the previous code.
The same iterator code works for all STL containers.
forward_list<char> l = {'a', 'c', 'k', 'J'}; for (auto it = l.begin(); it != l.end(); ++it) cout << *it;
ackJ
unordered_set<char> u = {'a', 'c', 'k', 'J'}; for (auto it = u.begin(); it != u.end(); ++it) cout << *it;
Jcka
set<char> s = {'a', 'c', 'k', 'J'}; for (auto it = s.begin(); it != s.end(); ++it) cout << *it;
Jack
iterator
typeset<int>::iterator
?
int *
, that’s for sure!
list<int>::iterator
and unordered_set<int>::iterator
.
operator++
is overloaded.
list
, set
, unordered_set
)
++
, --
, ==
, !=
, *
, ->
, =
std::array
, vector
, string
)
++
, --
,
+=
int, -=
int,
+
int, -
int,
iter-
iter,
==
, !=
,
<
, <=
,
>
, >=
,
*
, ->
, =
forward_list
)
++
, ==
, !=
, *
, ->
, =
begin()
& end()
.begin()
& .end()
return iterators. Not necessarily pointers.
.begin()
is, conceptually, a pointer to the
first element of the container.
.end()
is, conceptually, a pointer one past
the end of the container.
string s = "bonehead"; cout << "First character: " << *s.begin() << '\n'; cout << "This is wrong: " << *s.end() << '\n';
First character: b This is wrong: ␀
string s = "genius"; cout << "First character: " << *s.begin() << '\n'; cout << "Last character: " << *(s.end()-1) << '\n';
First character: g Last character: s
.front()
& .back()
Some containers have .front()
and .back()
, which return
references to the first and last elements.
list<double> c = {1.2, 3.4, 5.6}; cout << "First: " << c.front() << '\n'; cout << "Last: " << c.back() << '\n';
First: 1.2 Last: 5.6
These are not iterators.
This won’t work:
list<string> l = {"kappa", "alpha", "gamma"}; for (auto it = l.begin(); it < l.end(); ++it) cout << *it << ' ';
c.cc:2: error: no match for 'operator<' in 'it < l.std::__cxx11::list<std::__cxx11::basic_string<char> >::end()' (operand types are 'std::_List_iterator<std::__cxx11::basic_string<char> >' and 'std::__cxx11::list<std::__cxx11::basic_string<char> >::iterator' {aka 'std::_List_iterator<std::__cxx11::basic_string<char> >'})
This will work:
list<string> l = {"kappa", "alpha", "gamma"}; for (auto it = l.begin(); it != l.end(); ++it) cout << *it << ' ';
kappa alpha gamma
list<>::iterator
is a BidirectionalIterator, not a RandomAccessIterator,
and so <
isn’t defined. What would it compare? The addresses of the
linked list nodes? That’s not useful.
All containers accept a pair of iterators as ctor arguments. These do not have to be iterators for the same type of container.
char hhmmss[] = "024251"; // ISO 8601! string now(hhmmss, hhmmss+6); cout << now << '\n'; string mins(now.begin()+2, now.begin()+4); cout << mins << '\n'; multiset<int> ms(now.begin(), now.end()); for (auto n : ms) cout << n << ' '; cout << '\n';
024251 42 48 49 50 50 52 53
begin()
and end()
functionsThere are also free functions begin()
and end()
,
which work on arrays (not pointers) and all standard containers:
char now[] = "02:42am Fri"; string current(now, now+10); cout << current << '\n';
02:42am Fr
Oh dear, I counted wrong. Why am I counting!?
char now[] = "02:42am Fri"; string current(begin(now), end(now)); cout << current << '\n';
02:42am Fri␀