Могу ли я использовать указатель в циклах for в с ++? - PullRequest
1 голос
/ 06 августа 2020

Я знаю, что могу иметь любой тип для l oop для перебора:

#include <fstream>
#include <iostream>

using namespace std;

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

Но у меня не могло быть типа указателя:

#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;
}

даст:

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

Итак, я предполагаю, что синтаксис c ++ для l oop (auto var : vector/array) не совпадает с c -стилем, старомодным l oop for(int i=0; i<size; i++)? Потому что от меня требуется (в случае использования стиля С ++ для l oop) предоставить структуру с допустимым итератором (отсюда и ошибки, ищущие итераторы begin () и end (). Но тогда почему первый случай сработал? Первый случай, массив с целыми числами, также является структурой без каких-либо итераторов, но со старыми указателями (для доступа). Итак, почему первый подходит, а второй нет?

1 Ответ

2 голосов
/ 06 августа 2020

Разница в этих примерах скрыта внутри правил передачи параметров функциям.

В первом примере, когда вы пишете int ar[] = {1, 2, 3};, тип ar равен int[3] - "an массив из 3-х целых ". std::begin определен для массивов, поэтому код компилируется и работает.

Во втором примере char const *argv[] на самом деле то же самое, что char const **argv, потому что в параметрах функции вы не можете передать массив по значению , а синтаксис [] компилируется точно так же, как если бы вы использовали *. Очевидно, что для указателей нет std::begin, поэтому код не работает.

Чтобы перебрать аргументы, вам нужно будет использовать обычное для l oop. Например,

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

Edit: просто для пояснения - для использования диапазона l oop, std::begin(a) и std::end(a) должны быть вызываемыми и возвращать итератор. (не совсем верно, поскольку C ++ 17 - std::end может возвращать все, что сравнимо с итератором, это называется часовым в рабочем проекте C ++ 20)

В случай массива с известной границей (например, int[3]), std::begin возвращает указатель на первый элемент, а std::end возвращает указатель за концом. iterator в C ++ не обязательно должен быть производным классом какой-то специальной базы, он просто должен иметь правильную семантику. Указатели также являются итераторами .

...