У меня есть массив, int arr[5]
который передается в функцию fillarr(int arr[])
:
int fillarr(int arr[])
{
for(...);
return arr;
}
- Как я могу вернуть этот массив?
- Как я буду использовать его, скажем, я вернул указатель, как я собираюсь получить к нему доступ?
std::vector
.5
В подписи функции отбрасывается компилятором.Ответы:
В этом случае переменная вашего массива
arr
может фактически рассматриваться как указатель на начало блока вашего массива в памяти путем неявного преобразования. Этот синтаксис, который вы используете:Это просто синтаксический сахар. Вы могли бы действительно заменить это этим, и это все еще работало бы:
Таким образом, в том же смысле, то, что вы хотите вернуть из своей функции, это фактически указатель на первый элемент в массиве:
И вы все равно сможете использовать его так же, как обычный массив:
источник
array
и&array
взаимозаменяемы во многих случаях.a
вint a[10]
естьint[10]
. Вы можете сказать, что массивы «распадаются» на указатели на их первый элемент. (Это неявное преобразование массива в указатель.) Тогда ваш ответ будет идти в том же направлении, что и мой. Если вы отредактируете свой ответ, чтобы различать массивы, преобразование массива в указатель и указатели, я удалю свой ответ, поскольку они будут иметь ту же основную информацию, а вы были первыми.Функции C ++ не могут возвращать массивы в стиле C по значению. Самое близкое - вернуть указатель. Кроме того, тип массива в списке аргументов просто преобразуется в указатель.
Вы можете улучшить его, используя ссылки на массив для аргумента и возврата, что предотвращает затухание:
В Boost или C ++ 11 передача по ссылке является необязательной, а синтаксис менее утомительным:
array
Шаблон просто генерируетstruct
содержащий массив C-стиле, так что вы можете применить объектно-ориентированной семантикой еще сохраняют первоначальную простоту массива.источник
typedef int array[5]; array& foo();
Но вы даже не нужны ЬурейиЙ , если вы заботитесь , чтобы написать это:int (&foo())[5] { static int a[5] = {}; return a; }
, пример в этом вопросе будет:int (&foo( int (&a)[5] ))[5] { return a; }
. Просто, не правда ли?error: function returning array is not allowed
которое появляется, если вы пропустите внешние парены в синтаксисе не typedef. К счастью, сегодня я пересмотрел правое лево-правило для другого вопроса и сумел построить правильную вещь ... увидев, что вы говорите, что это возможно ... прежде чем увидеть, что вы дали код: vP.В C ++ 11 вы можете вернуться
std::array
.источник
(...) you can consider the array returned arr2, totally another array (...)
8,3,5 долл. США / 8 штатов
«Функции не должны иметь возвращаемый тип массива или функции типа, хотя они могут иметь возвращаемый тип указателя типа или ссылку на такие вещи. Не должно быть массивов функций, хотя могут быть массивы указателей на функции».
источник
int
, а не массив.Ответ может немного зависеть от того, как вы планируете использовать эту функцию. Для простейшего ответа давайте решим, что вместо массива вам действительно нужен вектор. Векторы хороши тем, что выглядят для всего мира как скучные, обычные значения, которые вы можете хранить в обычных указателях. Мы рассмотрим другие варианты и почему вы хотите их потом:
Это будет делать именно то, что вы ожидаете. Положительным моментом является то,
std::vector
что все должно быть сделано аккуратно. недостатком является то, что это копирует очень большой объем данных, если ваш массив большой. Фактически он копирует каждый элемент массива дважды. сначала он копирует вектор, чтобы функция могла использовать его в качестве параметра. затем он копирует его снова, чтобы вернуть его вызывающей стороне. Если вы можете справиться с управлением вектором самостоятельно, вы можете сделать вещи немного проще. (он может скопировать его в третий раз, если вызывающий объект должен сохранить его в какой-либо переменной для выполнения дополнительных вычислений)Похоже, что вы действительно пытаетесь сделать, это просто заполнить коллекцию. если у вас нет конкретной причины возвращать новый экземпляр коллекции, то не делайте этого. мы можем сделать это так
таким образом, вы получаете ссылку на массив, переданный функции, а не ее частную копию. любые изменения, которые вы вносите в параметр, видятся вызывающей стороной. Вы можете вернуть ссылку на него, если хотите, но это не очень хорошая идея, так как она подразумевает, что вы получаете что-то отличное от того, что вы прошли.
Если вам действительно нужен новый экземпляр коллекции, но вы хотите избежать его размещения в стеке (и всех копий, которые это влечет за собой), вам нужно создать какой-то контракт на обработку этого экземпляра. Самый простой способ сделать это - использовать умный указатель, который хранит ссылочный экземпляр, пока кто-нибудь его держит. Он уходит чисто, если выходит за рамки. Это будет выглядеть так.
По большей части, использование
*myArr
работает идентично использованию простого ванильного вектора. В этом примере также изменяется список параметров путем добавленияconst
ключевого слова. Теперь вы получаете ссылку, не копируя ее, но не можете ее изменить, поэтому вызывающая сторона знает, что она будет такой же, как и до того, как функция добралась до нее.Все это здорово, но идиоматический c ++ редко работает с коллекциями в целом. Обычно вы будете использовать итераторы для этих коллекций. это будет выглядеть примерно так
Использование выглядит немного странно, если вы не привыкли видеть этот стиль.
foo теперь указывает на начало модифицированного
arr
.Что действительно хорошо в этом, так это то, что он одинаково хорошо работает с вектором, как с простыми C-массивами и многими другими типами коллекций, например.
Который сейчас выглядит очень похоже на простые примеры указателей, приведенные в другом месте этого вопроса.
источник
&
символ должен появляться после типа:void fillarr(std::vector<int> & arr)
Это:
на самом деле рассматривается так же, как:
Теперь, если вы действительно хотите вернуть массив, вы можете изменить эту строку на
Это на самом деле не возвращает массив. вы возвращаете указатель на начало адреса массива.
Но помните, когда вы передаете массив, вы передаете только указатель. Поэтому, когда вы изменяете данные массива, вы фактически изменяете данные, на которые указывает указатель. Поэтому, прежде чем перейти в массив, вы должны понять, что у вас уже есть измененный результат снаружи.
например
Я полагаю, что вы можете рассмотреть возможность добавления длины в свою функцию fillarr следующим образом.
Таким образом, вы можете использовать длину, чтобы заполнить массив до его длины, независимо от того, что это такое.
На самом деле использовать его правильно. Сделайте что-то вроде этого:
Если все, что вы хотите сделать, это установить для массива некоторые значения по умолчанию, рассмотрите возможность использования встроенной функции memset.
что-то вроде: memset ((int *) & arr, 5, sizeof (int));
Пока я в теме, хотя. Вы говорите, что используете C ++. Посмотрите на использование векторов STL. Ваш код, вероятно, будет более надежным.
Есть много учебников. Вот тот, который дает вам представление о том, как их использовать. http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html
источник
std::copy
болееmemset
, это безопаснее и проще. (И так же быстро, если не быстрее.)чтобы вернуть массив из функции, давайте определим этот массив в структуре; Так это выглядит примерно так
Теперь давайте создадим переменные типа структуры.
Мы можем передать массив функции следующим образом и присвоить ей значение:
Мы также можем вернуть массив. Чтобы вернуть массив, возвращаемый тип функции должен иметь структурный тип, то есть метки. Это потому, что в действительности мы передаем структуру, которая содержит массив. Таким образом, окончательный код может выглядеть следующим образом.
источник
Это довольно старый вопрос, но я собираюсь поставить свои 2 цента, так как есть много ответов, но ни один из них не показывает все возможные методы в четкой и сжатой форме (не уверен насчет краткого, так как это получило немного вышел из-под контроля. TL; DR 😉).
Я предполагаю, что OP хотел вернуть массив, который был передан без копирования, в качестве средства прямой передачи его вызывающей стороне для передачи в другую функцию, чтобы код выглядел красивее.
Однако использовать такой массив - это позволить ему распадаться на указатель, а компилятор обрабатывать его. как массив. Это может привести к незначительным ошибкам, если вы передадите массив, например, с функцией, ожидающей, что он будет иметь 5 элементов, но ваш вызывающий код фактически передает другое число.
Есть несколько способов справиться с этим лучше. Передайте в
std::vector
или илиstd::array
(не уверен, чтоstd::array
был где-то в 2010 году, когда был задан вопрос). Затем вы можете передать объект в качестве ссылки без какого-либо копирования / перемещения объекта.Однако, если вы настаиваете на игре с массивами Си, используйте шаблон, который будет хранить информацию о количестве элементов в массиве.
За исключением того, что выглядит ужасно, и супер трудно читать. Теперь я использую кое-что, чтобы помочь с тем, чего не было в 2010 году, что я также использую для указателей функций:
Это перемещает тип, в котором можно было бы ожидать, делая это намного более читабельным. Конечно, использование шаблона является излишним, если вы не собираетесь использовать ничего, кроме 5 элементов, поэтому вы, конечно, можете жестко его кодировать:
Как я уже сказал, мой
type_t<>
трюк не сработал бы в то время, когда был задан этот вопрос. Лучшее, на что вы могли надеяться тогда, - это использовать тип в структуре:Который снова начинает казаться довольно уродливым, но, по крайней мере, все еще более читабельным, хотя в то время он
typename
мог быть необязательным в зависимости от компилятора, в результате чего:И тогда, конечно, вы могли бы указать конкретный тип, а не использовать мой помощник.
Тогда свободных функций
std::begin()
иstd::end()
не было, хотя их можно было легко реализовать. Это позволило бы выполнять итерации по массиву более безопасным способом, поскольку они имеют смысл для массива C, но не указателя.Что касается доступа к массиву, вы можете либо передать его другой функции, которая принимает тот же тип параметра, либо создать псевдоним для него (что не имеет большого смысла, поскольку у вас уже есть оригинал в этой области). Доступ к ссылке на массив аналогичен доступу к исходному массиву.
или
Подводя итог, лучше не допускать распада массива в указатель, если вы собираетесь его перебирать. Это просто плохая идея, так как она не дает компилятору защитить вас от удара ногой и затрудняет чтение кода. Всегда старайтесь помочь компилятору помочь вам, сохраняя типы как можно дольше, если только у вас нет веских причин не делать этого.
редактировать
Да, и для полноты вы можете разрешить его снижение до указателя, но это отделяет массив от числа элементов, которые он содержит. Это много делается в C / C ++ и обычно смягчается передачей количества элементов в массиве. Однако компилятор не может помочь вам, если вы допустили ошибку и передали неправильное значение числу элементов.
Вместо того, чтобы передавать размер, вы можете передать указатель конца, который будет указывать на один за концом вашего массива. Это полезно, так как это делает что-то похожее на алгоритмы std, которые принимают указатель начала и конца, но то, что вы возвращаете, теперь только то, что вы должны помнить.
Кроме того, вы можете задокументировать, что эта функция займет всего 5 элементов, и надеяться, что пользователь вашей функции не сделает глупостей.
Обратите внимание, что возвращаемое значение потеряло свой первоначальный тип и ухудшено до указателя. Из-за этого вы теперь сами по себе гарантируете, что не собираетесь переполнять массив.
Вы можете передать a
std::pair<int*, int*>
, который вы можете использовать для начала и конца и передать его, но тогда он действительно перестанет выглядеть как массив.или
Забавно, это очень похоже на
std::initializer_list
работу (c ++ 11), но они не работают в этом контексте.источник
Самый простой способ сделать это - вернуть его по ссылке, даже если вы не пишете символ «&», он автоматически возвращается по ссылке
источник
Вы все еще можете использовать результат как
источник
Как указано выше, пути верны. Но я думаю, что если мы просто возвращаем переменную локального массива функции, иногда она возвращает значения мусора в качестве своих элементов.
во избежание этого мне пришлось динамически создавать массив и продолжать. Что-то вроде этого.
источник
источник
Источник: https://www.tutorialspoint.com/cplusplus/cpp_return_arrays_from_functions.htm
C ++ не позволяет возвращать весь массив в качестве аргумента функции. Однако вы можете вернуть указатель на массив, указав имя массива без индекса.
Применяя эти правила к текущему вопросу, мы можем написать программу следующим образом:
Выход будет:
источник
и что насчет:
источник
На самом деле, когда вы передаете массив внутри функции, указатель на исходный массив передается в параметре функции и, таким образом, изменения, сделанные в массиве внутри этой функции, фактически вносятся в исходный массив.
Запустите его, и вы увидите изменения
источник
y
передается как ее копия, но, поскольку она является указателем, вы будете напрямую работать с массивом. Пожалуйста, отредактируйте свой ответ.Вот полный пример такого рода проблемы, чтобы решить
источник
Просто определите тип [] как возвращаемое значение, например:
, , , вызов функции:
источник