0

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?

5
  • If it's an array it can know the length so it knows how long the loop goes. If it's a pointer it has no idea where the array ends - it'd have to loop through all of RAM starting at the address given by argv. Commented Aug 5, 2020 at 22:38
  • @OliverDain that is, of course true, but that is not the question. I see no reference about the c++-for-loop to state, it needs only structure with iterators. And again, why then the first int-array case compiled? It also has no information about the size so as you are saying, the for loop would have to go through all RAM, but it compiled. So your statement is not true Commented Aug 5, 2020 at 22:42
  • I think this question has been answered multiple times on SO, for example here: stackoverflow.com/questions/15904896/… Commented Aug 5, 2020 at 22:44
  • @Bert The question is similar, but the answers there don't apply well, you can't replace argv with a std::vector or other container. Commented Aug 5, 2020 at 22:46
  • Although this could be useful. Commented Aug 5, 2020 at 22:47

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

10 Comments

Is it only for c++? the array-decaying to pointer, or does c handles it as well the same? I know I cannot pass an array by value
@milanHrabos This is something C++ copied from C.
@Barmar as far as I know, arrays as well as struct and local vairables are all stored in stack anyway. The only way it would not be stored in stack is case of pointer allocated by malloc (and thus in heap) and assign to that array.
@milanHrabos Where the array is stored is irrelevant to this. If you declare a global array it's not stored in the stack. The argv array is not in the stack.
@Barmar it is. It is actually pushed to stack before call to main (arg_n-1, arg_n-2, ... arg2, arg1, ret, call main, rbp, ...). Where other would you place arguments to main? or any other function? There are just 2 options - stack, and registers. The stack is more preferable (at least for x86)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.