milanHrabos
milanHrabos

Reputation: 1965

Can I use pointer in for loops in c++?

I know I can have any type in for loop to iterate over:

#include <fstream>
#include <iostream>

using namespace std;

int main()
{
    int ar[] ={ 1, 2, 3 };
    for (int i:ar)
    {
        cout << i << endl;
    }
}

But I could not have an pointer type:

#include <fstream>
#include <iostream>
#include <string>

using namespace std;

int main(int argc, char const *argv[])
{
    for (char *p:argv) //or better char const *p
    // using auto keyword expands to error-type in vscode
    {
        ifstream in(p);
    }

    return 0;
}

will give:

error: ‘begin’ was not declared in this scope
     for (char *p:argv)
error: ‘end’ was not declared in this scope
     for (char *p:argv)
                  ^~~~

So I am assuming, the syntax of c++ for loop (auto var : vector/array) is not the same as c-style, old-fashion loop for(int i=0; i<size; i++)? Because I am required (in case of using c++ style for loop) to provided a structure with valid iterator (thus the errors, looking for begin() and end() iterators. But then why did the first case works? The first case, an array with ints, is also a structure without any kind of iterators, but old pointers (to access). So why the first is okay, but the second isn't?

Upvotes: 0

Views: 866

Answers (1)

shananton
shananton

Reputation: 508

The difference in those samples is hidden inside the rules of passing parameters to functions.

In the first example, when you write int ar[] = {1, 2, 3};, the type of ar is int[3] - "an array of 3 ints". std::begin is defined for arrays, so the code compiles and works.

In the second example, char const *argv[] is actually the same as char const **argv, because in function parameters, you cannot pass an array by value, and the syntax [] is compiled exactly as if you would have used *. Obviously, there is no std::begin for pointers, so the code does not work.

To iterate over the arguments, you would have to use an ordinary for loop. For example,

for (int i = 0; i < argc; ++i) {
  char const* arg = argv[i];
};

Edit: Just to clarify - to use a range-based for loop, std::begin(a) and std::end(a) should be callable and return an iterator. (not entirely true since C++17 - std::end could return anything that is comparable with the iterator, this is called a sentinel in the C++20 working draft)

In case of an array with known bound (such as int[3]), std::begin returns a pointer to the first element, and std::end returns a pointer past-the-end. An iterator in C++ does not have to be a derived class of some special base, it just has to have the right semantics. Pointers are also iterators.

Upvotes: 1

Related Questions