Возвращаемый массив в функции

У меня есть массив int arr[5] который передается функции fillarr(int arr[]) :

 int fillarr(int arr[]) { for(...); return arr; } 
  1. Как я могу вернуть этот массив?
  2. Как я буду использовать его, скажем, я вернул указатель, как мне получить к нему доступ?

В этом случае ваша переменная array arr также может рассматриваться как указатель на начало блока вашего массива в памяти, путем неявного преобразования. Этот синтаксис, который вы используете:

 int fillarr(int arr[]) 

Является просто синтаксическим сахаром. Вы могли бы действительно заменить его этим, и он все равно будет работать:

 int fillarr(int* arr) 

Итак, в том же смысле, то, что вы хотите вернуть из своей функции, на самом деле является указателем на первый элемент массива:

 int* fillarr(int arr[]) 

И вы все равно сможете использовать его так же, как обычный массив:

 int main() { int y[10]; int *a = fillarr(y); cout << a[0] << endl; } 

Функции C ++ не могут возвращать массивы C-стиля по значению. Самое близкое – вернуть указатель. Кроме того, тип массива в списке аргументов просто преобразуется в указатель.

 int *fillarr( int arr[] ) { // arr "decays" to type int * return arr; } 

Вы можете улучшить его, используя ссылки массива для аргумента и возврата, что предотвращает распад:

 int ( &fillarr( int (&arr)[5] ) )[5] { // no decay; argument must be size 5 return arr; } 

С Boost или C ++ 11, передача по ссылке является необязательной, и синтаксис меньше ума:

 array< int, 5 > &fillarr( array< int, 5 > &arr ) { return arr; // "array" being boost::array or std::array } 

Шаблон array просто генерирует struct содержащую массив C-style, поэтому вы можете применить объектно-ориентированную семантику, но сохраните первоначальную простоту массива.

$ 8.3.5 / 8 государств-

«Функции не должны иметь тип возвращаемого типа массива или функции, хотя они могут иметь тип возвращаемого типа указателя типа или ссылки на такие вещи. Не должно быть массивов функций, хотя могут быть массивы указателей на функции».

 int (&fn1(int (&arr)[5]))[5]{ // declare fn1 as returning refernce to array return arr; } int *fn2(int arr[]){ // declare fn2 as returning pointer to array return arr; } int main(){ int buf[5]; fn1(buf); fn2(buf); } 

В C ++ 11 вы можете вернуть std::array .

 #include  using namespace std; array fillarr(int arr[]) { array arr2; for(int i=0; i<5; ++i) { arr2[i]=arr[i]*2; } return arr2; } 

ответ может зависеть от того, как вы планируете использовать эту функцию. Простейший ответ позволяет решить, что вместо массива вам нужен вектор. Векторы хороши, потому что вы смотрите на весь мир, как скучные, обычные значения, которые вы можете хранить в обычных указателях. Мы рассмотрим другие варианты и почему вы хотите их потом:

 std::vector fillarr( std::vector arr ) { // do something return arr; } 

Это будет делать именно то, что вы ожидаете от этого. Поверхность заключается в том, что std::vector заботится о том, чтобы все было обработано чисто. недостатком является то, что это копирует очень большой объем данных, если ваш массив большой. Фактически он копирует каждый элемент массива дважды. сначала он копирует вектор, чтобы функция могла использовать его в качестве параметра. затем он копирует его снова, чтобы вернуть его вызывающему. Если вы можете справиться с управлением вектором самостоятельно, вы можете сделать что-то более легко. (он может скопировать его в третий раз, если вызывающему нужно сохранить его в какой-либо переменной, чтобы сделать больше вычислений)

Похоже, что вы действительно пытаетесь сделать, просто заполнить коллекцию. если у вас нет конкретной причины возвращать новый экземпляр коллекции, тогда нет. мы можем сделать это так

 void fillarr(std::vector & arr) { // modify arr // don't return anything } 

таким образом вы получаете ссылку на массив, переданный функции, а не его частную копию. любые изменения, внесенные вами в параметр, отображаются вызывающим. Вы можете вернуть ссылку на него, если хотите, но это не очень хорошая идея, так как это подразумевает, что вы получаете что-то отличное от того, что вы прошли.

Если вам действительно нужен новый экземпляр коллекции, но вы хотите избежать его в стеке (и все это влечет за собой), вам нужно создать какой-то контракт для обработки этого экземпляра. самый простой способ сделать это – использовать интеллектуальный указатель, который сохраняет экземпляр, на который ссылается, до тех пор, пока кто-то держит его. Он уходит чисто, если он выходит за frameworks. Это будет выглядеть так.

 std::auto_ptr > fillarr( const std::vector & arr) { std::auto_ptr > myArr(new std::vector); // do stuff with arr and *myArr return myArr; } 

По большей части использование *myArr работает одинаково с использованием простого вектора ванили. Этот пример также изменяет список параметров, добавляя ключевое слово const . Теперь вы получаете ссылку, не копируя ее, но вы не можете ее изменить, поэтому вызывающий абонент знает, что она будет такой же, как до того, как функция добралась до нее.

Все это набухает, но идиоматический c ++ редко работает с коллекциями в целом. Как правило, вы будете использовать iteratorы над этими коллекциями. это будет выглядеть примерно так

 template  Iterator fillarr(Iterator arrStart, Iterator arrEnd) { Iterator arrIter = arrStart; for(;arrIter <= arrEnd; arrIter++) ;// do something return arrStart; } 

Использование этого выглядит немного странно, если вы не привыкли видеть этот стиль.

 vector arr; vector::iterator foo = fillarr(arr.begin(), arr.end()); 

foo теперь «указывает на» начало модифицированного arr .

Что действительно приятно в том, что он работает одинаково хорошо на векторе, как на простых C-массивах и многих других типах коллекции, например

 int arr[100]; int *foo = fillarr(arr, arr+100); 

Который теперь выглядит ужасно похожим на простые примеры указателей, приведенные в другом месте этого вопроса.

Эта:

 int fillarr(int arr[]) 

фактически обрабатывается так же, как:

 int fillarr(int *arr) 

Теперь, если вы действительно хотите вернуть массив, вы можете изменить эту строку на

 int * fillarr(int arr[]){ // do something to arr return arr; } 

Это не возвращает массив. вы возвращаете указатель на начало адреса массива.

Но помните, когда вы проходите массив, вы только передаете указатель. Поэтому, когда вы изменяете данные массива, вы фактически изменяете данные, на которые указывает указатель. Поэтому, прежде чем вы пройдете в массиве, вы должны понять, что у вас уже есть внешний результат.

например

 int fillarr(int arr[]){ array[0] = 10; array[1] = 5; } int main(int argc, char* argv[]){ int arr[] = { 1,2,3,4,5 }; // arr[0] == 1 // arr[1] == 2 etc int result = fillarr(arr); // arr[0] == 10 // arr[1] == 5 return 0; } 

Я предлагаю вам подумать о том, чтобы положить длину в вашу функцию fillarr, как это.

 int * fillarr(int arr[], int length) 

Таким образом, вы можете использовать длину, чтобы заполнить массив до его длины независимо от того, что это такое.

Чтобы правильно использовать его. Сделайте что-то вроде этого:

 int * fillarr(int arr[], int length){ for (int i = 0; i < length; ++i){ // arr[i] = ? // do what you want to do here } return arr; } // then where you want to use it. int arr[5]; int *arr2; arr2 = fillarr(arr, 5); // at this point, arr & arr2 are basically the same, just slightly // different types. You can cast arr to a (char*) and it'll be the same. 

Если все, что вы хотите сделать, это установить массив на некоторые значения по умолчанию, рассмотрите возможность использования встроенной функции memset.

что-то вроде: memset ((int *) & arr, 5, sizeof (int));

Хотя я по теме. Вы говорите, что используете C ++. Посмотрите на использование векторов stl. Ваш код, скорее всего, будет более надежным.

Есть много учебников. Вот один из них, который дает вам представление о том, как их использовать. http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html

для возврата массива из функции, определим этот массив в структуре; Так выглядит что-то вроде этого

 struct Marks{ int list[5]; } 

Теперь создадим переменные структуры типа.

 typedef struct Marks marks; marks marks_list; 

Мы можем передать массив в функцию следующим образом и присвоить ему значение:

 void setMarks(int marks_array[]){ for(int i=0;i 

Мы также можем вернуть массив. Чтобы вернуть массив, возвращаемый тип функции должен быть типа структуры, т.е. меток. Это связано с тем, что в действительности мы передаем структуру, содержащую массив. Таким образом, окончательный код может выглядеть так.

 marks getMarks(){ return marks_list; } 

Самый простой способ сделать это – вернуть его по ссылке, даже если вы не пишете символ «&», он автоматически возвращается ссылкой

  void fillarr(int arr[5]) { for(...); } 

Это довольно старый вопрос, но я собираюсь поставить свои 2 цента, так как есть много ответов, но ни один из них не показывает все возможные методы в ясной и сжатой форме (не уверен в краткости, поскольку это получило бит из-под контроля. TL; DR 😉).

Я предполагаю, что OP хотел вернуть массив, который был передан без копирования, как некоторые средства прямого передачи этого вызывающему, который должен быть передан другой функции, чтобы код выглядел красивее.

Тем не менее, использовать такой массив, чтобы позволить ему распадаться на указатель, и компилятор рассматривает его как массив. Это может привести к тонким ошибкам, если вы передадите массив, например, с функцией, ожидающей, что она будет содержать 5 элементов, но ваш вызывающий абонент действительно передает какой-то другой номер.

Есть несколько способов справиться с этим лучше. Перейдите в std::vector или std::array (не уверен, что std::array был в 2010 году, когда задавался вопрос). Затем вы можете передать объект в качестве ссылки без какого-либо копирования / перемещения объекта.

 std::array& fillarr(std::array& arr) { // (before c++11) for(auto it = arr.begin(); it != arr.end(); ++it) { /* do stuff */ } // Note the following are for c++11 and higher. They will work for all // the other examples below except for the stuff after the Edit. // (c++11 and up) for(auto it = std::begin(arr); it != std::end(arr); ++it) { /* do stuff */ } // range for loop (c++11 and up) for(auto& element : arr) { /* do stuff */ } return arr; } std::vector& fillarr(std::vector& arr) { for(auto it = arr.begin(); it != arr.end(); ++it) { /* do stuff */ } return arr; } 

Однако, если вы настаиваете на игре с массивами C, используйте шаблон, который будет содержать информацию о количестве элементов в массиве.

 template  int(&fillarr(int(&arr)[N]))[N] { // N is easier and cleaner than specifying sizeof(arr)/sizeof(arr[0]) for(int* it = arr; it != arr + N; ++it) { /* do stuff */ } return arr; } 

Кроме того, что выглядит прикладом уродливым, и супер трудно читать. Теперь я использую что-то, чтобы помочь с тем, чего не было в 2010 году, которое я также использую для указателей функций:

 template  using type_t = T; template  type_t fillarr(type_t arr) { // N is easier and cleaner than specifying sizeof(arr)/sizeof(arr[0]) for(int* it = arr; it != arr + N; ++it) { /* do stuff */ } return arr; } 

Это перемещает тип, который можно было бы ожидать, делая это намного более удобочитаемым. Конечно, использование шаблона является излишним, если вы не собираетесь использовать ничего, кроме 5 элементов, поэтому вы можете, конечно, жестко его кодировать:

 type_t fillarr(type_t arr) { // Prefer using the compiler to figure out how many elements there are // as it reduces the number of locations where you have to change if needed. for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it) { /* do stuff */ } return arr; } 

Как я уже сказал, мой type_t<> не работал бы в то время, когда задавался этот вопрос. Лучшее, на что вы могли надеяться, было использовать тип в структуре:

 template struct type { typedef T type; }; typename type::type fillarr(typename type::type arr) { // Prefer using the compiler to figure out how many elements there are // as it reduces the number of locations where you have to change if needed. for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it) { /* do stuff */ } return arr; } 

Который начинает выглядеть довольно уродливым, но, по крайней мере, он еще более читабельен, хотя typename может быть необязательным тогда в зависимости от компилятора, в результате чего:

 type::type fillarr(type::type arr) { // Prefer using the compiler to figure out how many elements there are // as it reduces the number of locations where you have to change if needed. for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it) { /* do stuff */ } return arr; } 

И тогда, конечно, вы могли бы указать определенный тип, а не использовать моего помощника.

 typedef int(&array5)[5]; array5 fillarr(array5 arr) { // Prefer using the compiler to figure out how many elements there are // as it reduces the number of locations where you have to change if needed. for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it) { /* do stuff */ } return arr; } 

Тогда свободные функции std::begin() и std::end() не существовали, хотя их можно было легко реализовать. Это позволило бы итерации по массиву более безопасно, поскольку они имеют смысл на массиве C, но не на указателе.

Что касается доступа к массиву, вы можете либо передать его другой функции, которая принимает тот же тип параметра, либо сделать ему псевдоним (что не имеет большого смысла, поскольку у вас уже есть оригинал в этой области). Доступ к ссылке массива аналогичен доступу к исходному массиву.

 void other_function(type_t x) { /* do something else */ } void fn() { int array[5]; other_function(fillarr(array)); } 

или

 void fn() { int array[5]; auto& array2 = fillarr(array); // alias. But why bother. int forth_entry = array[4]; int forth_entry2 = array2[4]; // same value as forth_entry } 

Подводя итог, лучше не допускать разложение массива в указатель, если вы намереваетесь перебирать его. Это всего лишь плохая идея, так как это препятствует компилятору защитить вас от стрельбы в ногу и делает ваш код более трудным для чтения. Всегда старайтесь и помогайте компилятору помочь вам, сохраняя типы как можно дольше, если у вас нет веских оснований не делать этого.

редактировать

О, и для полноты, вы можете позволить ему ухудшаться до указателя, но это отделяет массив от количества элементов, которые он удерживает. Это много сделано в C / C ++ и обычно смягчается путем передачи числа элементов в массиве. Однако компилятор не может помочь вам, если вы допустили ошибку и передаете неправильное значение количеству элементов.

 // separate size value int* fillarr(int* arr, size_t size) { for(int* it = arr; it != arr + size; ++it) { /* do stuff */ } return arr; } 

Вместо того, чтобы передавать размер, вы можете передать конечный указатель, который будет указывать на один конец конца вашего массива. Это полезно, поскольку оно делает что-то более близкое к алгоритмам std, которые берут указатель начала и конца, но то, что вы возвращаете, теперь только то, что вы должны помнить.

 // separate end pointer int* fillarr(int* arr, int* end) { for(int* it = arr; it != end; ++it) { /* do stuff */ } return arr; } 

Кроме того, вы можете записать, что эта функция будет принимать только 5 элементов и надеется, что пользователь вашей функции не сделает ничего глупого.

 // I document that this function will ONLY take 5 elements and // return the same array of 5 elements. If you pass in anything // else, may nazal demons exit thine nose! int* fillarr(int* arr) { for(int* it = arr; it != arr + 5; ++it) { /* do stuff */ } return arr; } 

Обратите внимание, что возвращаемое значение потеряло его первоначальный тип и ухудшено до указателя. Из-за этого вы теперь сами по себе, чтобы убедиться, что вы не собираетесь перехватывать массив.

Вы можете передать std::pair , который вы можете использовать для начала и конца и передать это, но тогда он действительно перестает выглядеть как массив.

 std::pair fillarr(std::pair arr) { for(int* it = arr.first; it != arr.second; ++it) { /* do stuff */ } return arr; // if you change arr, then return the original arr value. } void fn() { int array[5]; auto array2 = fillarr(std::make_pair(&array[0], &array[5])); // Can be done, but you have the original array in scope, so why bother. int fourth_element = array2.first[4]; } 

или

 void other_function(std::pair array) { // Can be done, but you have the original array in scope, so why bother. int fourth_element = array2.first[4]; } void fn() { int array[5]; other_function(fillarr(std::make_pair(&array[0], &array[5]))); } 

Забавно, это очень похоже на то, как работает std::initializer_list (c ++ 11), но в этом контексте они не работают.

 int *fillarr(int arr[]) 

Вы можете использовать результат, как

 int *returned_array = fillarr(some_other_array); if(returned_array[0] == 3) do_important_cool_stuff(); 
 template using ARR_REF = T (&)[N]; template  ARR_REF ArraySizeHelper(ARR_REF arr); #define arraysize(arr) sizeof(ArraySizeHelper(arr)) 

Источник: https://www.tutorialspoint.com/cplusplus/cpp_return_arrays_from_functions.htm

C ++ не позволяет возвращать весь массив в качестве аргумента функции. Однако вы можете вернуть указатель на массив, указав имя массива без индекса.

  1. Если вы хотите вернуть одномерный массив из функции, вам нужно объявить функцию, возвращающую указатель, как в следующем примере:
 int * myFunction() { . . . } 
  1. C ++ не защищает адрес локальной переменной вне функции, поэтому вам нужно будет определить локальную переменную как статическую.

Применяя эти правила по текущему вопросу, мы можем написать программу следующим образом:

 # include  using namespace std; int * fillarr( ); int main () { int *p; p = fillarr(); for ( int i = 0; i < 5; i++ ) cout << "p[" << i << "] : "<< *(p + i) << endl; return 0; } int * fillarr( ) { static int arr[5]; for (int i = 0; i < 5; ++i) arr[i] = i; return arr; } 

Выход будет:

 p[0]=0 p[1]=1 p[2]=2 p[3]=3 p[4]=4 

и что насчет:

 int (*func()) { int *f = new int[10] {1,2,3}; return f; } int fa[10] = { 0 }; auto func2() -> int (*) [10] { return &fa; } 

Просто определите тип [] как возвращаемое значение, например:

  private string[] functionReturnValueArray(string one, string two) { string[] x = {one, two}; x[0] = "a"; x[1] = "b"; return x; } 

, , , вызов функции:

 string[] y; y = functionReturnValueArray(stringOne, stringTwo) 
  • Вычисление средней функции массива Swift
  • Как просмотреть исходный код для функции?
  • Как вернуть строковое значение из функции Bash
  • strdup () - что он делает в C?
  • Есть ли встроенный просмотрщик функций экспорта DLL?
  • Ошибка: не удалось найти функцию ... в R
  • Процедура с аргументом фиктивного аргумента предполагаемой формы должна иметь явный интерфейс
  • Вычисление перекрестного произведения двух векторов в Fortran 90
  • Использование boost-streamа и нестатической функции classа
  • Заполните непересекающиеся пустые ячейки со значением из ячейки над первым пробелом
  • «Правильный» способ указать необязательные аргументы в R-функциях
  • Interesting Posts

    Как перенести hdd установки Windows на новый компьютер?

    Как заблокировать веб-сайты в Windows 8 без дополнительного программного обеспечения?

    Delphi: idHttp + SSL

    Выполнение static_assert, что тип шаблона является другим шаблоном

    Не удается найти значение размера BagMRU, настройки моей папки теряются

    Как в диалоговом окне «Запуск» известно, где находятся приложения?

    Как связать 2 модели с одним полем ввода в Angular?

    Android в покупке приложения: проверка подписи не выполнена

    Длинные команды, разделенные на несколько строк в пакетном (.bat) файле Windows Vista

    Рекомендации по эффективному стилю в React.js

    Не удается удалить раздел в diskpart – недопустимый аргумент?

    Декартовы данные продукта в R

    node.js есть ли подходящий способ parsingа JSON с большими числами? (long, bigint, int64)

    Как убить сессию ssh, связанную с созданием / отключением?

    Получение «отлаживаемого» значения androidManifest из кода?

    Давайте будем гением компьютера.