There are basically two ways. First one is a loop somewhere . The loop can be explicit - in your code - or it can be implicit through library. Example of library loop:
std::for_each(cbegin(arra), cend(arra), [](int i) {std::cout << "i ";});
The second way of printing the array is with the use of recursion. Here is example of the code:
void print_element(const int* head, const int* tail) {
if (head == tail)
return;
std::cout << *head << " ";
print_element(head + 1, tail);
}
....
print_element(arr, arr + sizeof(arr) / sizeof(*arr));
Couple of words about recursion solution. Depending on your optimization, it can produce different results. Performance of the recursion will be roughly equivalent to the performance of the loop on any optimization level with AMD64 ABI. The reason for that is that arguments to functions are passed through registers (not pushed into stack), and the frame pointers are not used with any optimization. With this in mind, the only CALL/RET (which push/pop RIP) will slow down execution compared the loop, but this degradation is not measurable. The real issue, however, is that there is limited number of recursed calls which can be made on a given system (usually around single thousands), so printing an array of 1000000 elements is guaranteed to crash the application.
With higher levels of optimization which involve tail-call optimization, the recursion calls will be translated into plain jmps and the performance will be exactly the same as one with the loop. It will also eliminate the problem of maximum recursion level - so that arrays of any sizes can be printed.