У меня есть метод, который получает переменную int. Эта переменная составляет размер массива (пожалуйста, не предлагайте мне вектор). Таким образом, мне нужно инициировать const int внутри моего метода для инициализации массива определенного размера. Вопрос: как мне это сделать?
void foo(int variable_int){
int a[variable_int] = {0}; //error
}
int *a = new int[variable_int];
Не забудьте удалить [] выделенное место, когда вы закончите с ним!
C ++ не поддерживает массивы переменной длины. Вместо этого вам нужно динамически распределять массив:
std::vector<int> a(variable_int);
или поскольку вы говорите, что по какой-то причине не хотите использовать вектор:
class not_a_vector
{
public:
explicit not_a_vector(size_t size) : a(new int[size]()) {}
~not_a_vector() {delete [] a;}
int & operator[](size_t i) {return a[i];}
int operator[](size_t i) const {return a[i];}
not_a_vector(not_a_vector const &) = delete;
void operator=(not_a_vector const &) = delete;
private:
int * a;
};
not_a_vector a(variable_int);
ОБНОВЛЕНИЕ: вопрос был только что обновлен с тегом «C» так же как «C ++». C (с 1999 года) поддерживает массивы переменной длины, поэтому ваш код должен хорошо работать на этом языке.
Вы просили не векторное решение, но давайте рассмотрим его, потому что вы могли отклонить его по неправильным причинам. Вы не должны беспокоиться о производительности, потому что в руках любого компетентного компилятора он будет иметь почти такие же издержки, что и любое другое стандартное совместимое решение. С другой стороны, есть некоторые проблемы с удобочитаемостью и безопасностью, о которых я расскажу ниже. Давайте посмотрим, как вы можете сделать это от наиболее рекомендуемого до минимального.
Любимый контейнер сообщества и по уважительной причине. Он не только может быть объявлен с размером времени выполнения, но и может быть изменен в любое время. Это облегчает использование, когда размер не может быть заранее определен, например, при многократном опросе для пользовательского ввода. Примеры:
// Known size
size_t n;
std::cin >> n;
std::vector<int> vec(n);
// Unknown size
std::vector<int> vec;
int input;
while (std::cin >> input) { // Note: not always the best way to read input
vec.push_back(in);
}
Там не так много недостатков в использовании std::vector
, Случай известного размера требует ровно одного динамического размещения. Неизвестный размер требует большего в общем случае, но вы все равно не сможете добиться большего. Так что производительность более или менее оптимальна.
Семантически, он не может быть идеальным для размеров, которые являются постоянными на протяжении всего выполнения. Читателю может быть не очевидно, что этот контейнер не предназначен для изменения. Это не известно компилятору, так что это позволит вам сделать что-то не так, как push_back
в vector
это логически постоянного размера.
Самое безопасное решение, если для вас важен статический размер.
size_t n;
std::cin >> n;
auto arr = std::make_unique<int[]>(n);
arr
Размер не может быть изменен, хотя это может быть сделано для освобождения текущего массива и указания на другой массив другого размера. Поэтому, если логически размер вашего контейнера постоянен, это передает намерение более ясным способом. К сожалению, это также намного слабее, чем std::vector
даже в случае постоянного размера. Он не учитывает размер, поэтому вы должны явно сохранить размер. По той же причине он не предлагает итераторов и не может использоваться в диапазоне для циклов. Это зависит от вас (и рассматриваемого проекта), если вы хотите пожертвовать этими функциями для обеспечения статического размера.
Первоначально я рекомендовал boost::scoped_array
но после дальнейших размышлений я не верю, что в этом решении есть что предложить, поэтому я буду придерживаться стандартной библиотеки.
Технически это решение, но если вы не вынуждены использовать старый стандарт C ++ или не пишете низкоуровневую библиотеку, которая управляет памятью внутри, они строго хуже, чем std::unique_ptr
или же std::shared_ptr
решение. Они не предлагают больше функций, но значительно менее безопасны, потому что вы должны явно освободить память, когда закончите с ней. В противном случае вы утечете, и это может вызвать серьезные проблемы. Что еще хуже, используя delete[]
правильно может быть нетривиальным для программ со сложными потоками выполнения и обработки исключений. Пожалуйста, не используйте это, когда вышеупомянутые решения доступны для вас!
size_t n;
std::cin >> n;
int* arr = new int[n];
...
// Control flow must reach exactly one corresponding delete[] !!!
delete[] arr;
Некоторые компиляторы могут быть в порядке со следующим кодом
size_t n;
std::cin >> n;
int arr[n];
Полагаться на это имеет серьезные недостатки. Ваш код не может быть скомпилирован на всех совместимых C ++ компиляторах. Вероятно, он даже не компилируется на всех версиях данного компилятора. Также я сомневаюсь, что созданный исполняемый файл проверяет значение n
и распределяет в куче при необходимости, что означает, что вы можете взорвать свой стек. Это решение имеет смысл только тогда, когда вы знаете верхнюю границу n
мала, и когда производительность настолько важна для вас, что вы готовы полагаться на специфичное для компилятора поведение, чтобы получить ее. Это действительно исключительные случаи.
Вы можете легко сделать константную переменную из неконстантной переменной, написав const int bar = variable_int;
— однако это вам не поможет. В C ++ размер массива с автоматическим хранением должен быть время компиляции постоянная. Вы не можете превратить переменную в константу времени компиляции, поэтому то, что вы хотите, просто невозможно.
В зависимости от ваших потребностей, вы можете сделать a
указатель и выделить память, используя new
(а потом delete
это) или, если параметр foo
всегда будет известен во время компиляции, вы можете включить foo
в шаблонной функции, как это:
template<int n> void foo() {
int a[n] = {0};
}
Чтобы делать то, что вы хотите, вам нужно будет использовать динамическое распределение. В этом случае я бы серьезно предложил использовать вектор — это «правильная» вещь в C ++.
Но если вы все еще не хотите использовать вектор [почему бы вам не выйти за рамки меня], правильный код:
void foo(int variable_int){
int *a = new int[variable_int](); // Parenthesis to initialize to zero.
... do stuff with a ...
delete [] a;
}
Как предлагают другие, вы также можете использовать calloc, который имеет тот же эффект инициализации в ноль, но на самом деле это не решение «c ++».
Если вы используете массивы, рекомендуется инкапсулировать их:
template<typename Type>
class Vector {
//...
};
Стандартная библиотека поставляется с реализацией: станд :: вектор