#c #arrays #pointers
#c #массивы #указатели
Вопрос:
Текстовое сообщение об ошибке:
Я изучаю книгу C Primer и сталкиваюсь с проблемой, указанной ниже, при написании ответа для одного упражнения:
#include<iostream>
#include<vector>
using namespace std;
int main() {
int i = 3;
const int ci = 3;
size_t si = 3;
const size_t csi = 3;
int ia[i];
int cia[ci];
int sia[si];
int csia[csi];
int another_a[] = {1,2,3};
int *pi = begin(ia); // error here
// no instance of overloaded function "begin" matches the argument list --
// argument types are: (int [i])
int *pci = begin(cia);
int *psi = begin(sia); // error here
// no instance of overloaded function "begin" matches the argument list --
// argument types are: (int [si])
int *pcsi = begin(csia);
int *p_ano = begin(another_a);
vector<int> v = {1,3,4};
const int m = v.size();
const size_t n = v.size();
int ma[m];
int na[n];
int *pm = begin(ma); // error here
// no instance of overloaded function "begin" matches the argument list --
// argument types are: (int [m])
int *pn = begin(na); // error here
// no instance of overloaded function "begin" matches the argument list --
// argument types are: (int [n])
system("pause");
return 0;
}
Я могу понять, что первые две ошибки связаны с тем, что эти два массива не определены с использованием постоянной переменной.
Но почему в последних двух, даже если я преобразовал размер вектора в постоянную переменную, компилятор все равно выдает ошибку?
Я совершенно сбит с толку этим, я был бы очень признателен за ваш любезный ответ или обсуждение, независимо от того, работает это или нет.
Комментарии:
1. Объявление массивов с непостоянными индексами не является стандартом c . Если вам нужны массивы с динамическим размером, используйте
std::vector
2. Вы должны публиковать сообщения об ошибках или (лучше) соответствующий журнал сборки, включая версию компилятора в виде текста.
3. Я знаю, что я должен использовать const var для объявления массива, но я думаю, что на шаге «const size_t n = v.size()» я уже вычислил результат и сохранил его в const var.
4. Для массивов @GavinXu требуется константа времени компиляции (проще говоря, значение, которое может быть вычислено компилятором). У вас есть постоянная переменная, которая отличается. Компилятор не может обрабатывать размер произвольного вектора, пока программа не будет запущена.
5. @john Хотя код может выполняться нормально на этапе выполнения, но на этапе компиляции это объявление недопустимо. Это то, что вы имеете в виду, верно? Я понял!!! Большое спасибо!!!
Ответ №1:
Прежде всего, вы используете расширение компилятора, но подробнее об этом позже.
Стандартная begin
перегрузка, которая работает для вас, — это шаблон, который принимает ссылку на массив размером, являющимся постоянным выражением. В двух словах, константные выражения — это те выражения, которые компилятор может оценить и узнать значение во время компиляции.
Постоянное целое число, инициализированное постоянным выражением типа const int ci = 3;
, может использоваться везде, где требуется постоянное выражение. So ci
— это, по сути, само константное выражение (равное 3).
В современном C есть способ выделить такие переменные в качестве предполагаемых постоянных выражений, это constexpr
спецификатор. Итак, вы могли бы определить ci
следующим образом:
constexpr int ci = 3;
Это точно так же, как ваш исходный код. Но то же самое не будет работать для const int m = v.size();
. Потому что constexpr
требуется истинное постоянное выражение в качестве инициализатора, в отличие от const
. Для const
переменной не обязательно постоянное выражение. Это может быть просто переменная времени выполнения, которую вы не можете изменить. И это в случае с m
.
Поскольку m
это не постоянное выражение, то, что вы определили, является массивом переменной длины. Функция C, которая иногда вводится компиляторами C в качестве расширения. И это не соответствует std::begin
шаблону, который ожидает, что экстент массива будет постоянным выражением.
Комментарии:
1. Таким образом, размерность массива должна быть выражением константы времени компиляции, но не константой времени выполнения, верно? Если да, то теперь я знаю причину. Большое вам спасибо за ваше любезное и подробное объяснение!
2. @GavinXu — Еще одна вещь. Я не знаю, что вы используете для компиляции вашего кода, но у большинства компиляторов есть опции для отключения расширений. Вам следует посмотреть, как можно настроить ваш, чтобы избежать расширений. Это очень полезно при изучении того, что является стандартным, а что нет, и компилятор может сказать вам, если вы спросите.
3. Например, GCC будет жаловаться, если вы добавите
-std=c 14 -pedantic-errors
4. Я просто использовал VS-code extensions C / C для изучения и настроил его в соответствии с некоторыми руководствами в Интернете. Спасибо за дополнительную информацию. И есть ли у вас какие-либо рекомендации? Должен ли я напрямую использовать Visual Studio?
5. @GavinXu — Вам не обязательно использовать полный VS. Я никогда не использовал VS-code, но слышал, что это неплохо. Просто проведите небольшое исследование, как настроить его, чтобы избежать расширений. Это поможет вам в обучении, и как только вы кое-что узнаете, вы сможете принять сознательное решение включить расширения.
Ответ №2:
Объявление массивов с непостоянными индексами не является стандартом c .
Если вам нужны массивы с динамическим размером, используйте std::vector
.
Объявление переменной как const
не делает ее константой времени компиляции (необходимой для объявления массива фиксированного размера), это просто означает, что вы не можете изменить ее после ее объявления.
Комментарии:
1. Я понял это. Большое спасибо за вашу иллюстрацию!