An array of elements of type char can be declared like this:
char v[6]; // array of 6 characters
Similarly, a pointer can be declared like this:
char* p; // pointer to character
In declarations, [] means ‘‘array of’’ and *means ‘‘pointer to.’’ All arrays have0as their lower bound, so v has six elements, v[0] to v[5] . The size of an array must be a constant expression. A pointer variable can hold the address of an object of the appropriate type:
char∗ p = &v[3]; // p указывает на четвёртый элемент массива v char x = ∗p; // *p является объектом, на который указывает p
In an expression, prefix unary ∗ means ‘‘contents of’’ and prefix unary & means ‘‘address of.’’ We can represent the result of that initialized definition graphically:
Consider copying ten elements from one array to another:
void copy_fct() { int v1[10] = {0,1,2,3,4,5,6,7,8,9}; int v2[10]; // to become a copy of v1 for (auto i=0; i!=10; ++i) // copy elements v2[i]=v1[i]; }
This for -statement can be read as ‘‘set i to zero; while i is not 10 , copy the i th element and increment i.’’ When applied to an integer variable, the increment operator, ++ , simply adds 1 . C++11 also offers a simpler for -statement, called a range-for-statement, for loops that traverse a sequence in the simplest way:
void print() { int v[] = {0,1,2,3,4,5,6,7,8,9}; for (auto x : v) cout << x << '\n'; // for each x in v for (auto x : {10,21,32,43,54,65}) cout << x << '\n'; }
The first range-for-statement can be read as ‘‘for every element of v , from the first to the last, place a copy in x and print it.’’ Note that we don’t hav e to specify an array bound when we initialize it with a list. The range-for-statement can be used for any sequence of elements.
If we didn’t want to copy the values from v into the variable x, but rather just have x refer to an element, we could write:
void increment() { int v[] = {0,1,2,3,4,5,6,7,8,9}; for (auto& x : v) ++x; }
In a declaration, the unary suffix & means ‘‘reference to.’’ A reference is similar to a pointer, except that you don’t need to use a prefix * to access the value referred to by the reference.
T a[n]; // array of n Ts T∗ p; // pointer to T T& r; // reference to T T f(A); // function taking an argument of type A returning a result of type T
We try to ensure that a pointer always points to an object, so that dereferencing it is valid. When we don’t hav e an object to point to or if we need to represent the notion of ‘‘no object available’’ (e.g., for an end of a list), we give the pointer the value nullptr (‘‘the null pointer’’). There is only one nullptr shared by all pointer types:
double∗ pd = nullptr; Link<Record>∗ lst = nullptr; // pointer to a Link to a Record int x = nullptr; // error : nullptr is a pointer not an integer
It is often wise to check that a pointer argument that is supposed to point to something, actually points to something:
int count_x(char∗ p, char x) // count the number of occurrences of x in p[] // p is assumed to point to a zero-ter minated array of char (or to nothing) { if (p==nullptr) return 0; int count = 0; for (; ∗p!=0; ++p) if (∗p==x) ++count; return count; }
Note how we can move a pointer to point to the next element of an array using ++ and that we can leave out the initializer in a for-statement if we don’t need it.
In older code, 0 or NULL is typically used instead of nullptr. However, using nullptr eliminates potential confusion between integers (such as 0 or NULL ) and pointers (such as nullptr ).