Zwraca tablicę w funkcji

212

Mam tablicę, int arr[5]która jest przekazywana do funkcji fillarr(int arr[]):

int fillarr(int arr[])
{
    for(...);
    return arr;
}
  1. Jak mogę zwrócić tę tablicę?
  2. Jak mam z niego korzystać, powiedzmy, że zwróciłem wskaźnik, w jaki sposób mam uzyskać do niego dostęp?
Ismail Marmoush
źródło
46
ściśle mówiąc, w tym kontekście nie trzeba zwracać tablicy, ponieważ tablica jest przekazywana przez referencję, więc wszelkie zmiany elementów wewnątrz „arr” będą widoczne poza funkcją.
BuggerMe,
12
zwracanie tablicy jest wygodne dla funkcji łączenia.
piątek
5
Dopóki nie popełnisz błędu, tworząc tablicę na stosie i zwracając do niej wskaźnik.
detly,
2
@ismail: Nie może zwrócić nowej tablicy, chyba że tablica ta została przydzielona dynamicznie. A jeśli tak jest, użyj std::vector.
GManNickG
4
@BuggerMe: Tablice nie są przekazywane przez odwołanie (chyba że zażądasz ich o wiele śmieszniejszej składni), w kodzie tablica rozpada się na wskaźnik do pierwszego elementu, który jest przekazywany do funkcji. 5W podpisie funkcja jest odrzucana przez kompilator.
David Rodríguez - dribeas

Odpowiedzi:

204

W takim przypadku zmienna tablicowa arrmoże być faktycznie traktowana jako wskaźnik do początku bloku tablicy w pamięci, poprzez niejawną konwersję. Ta składnia, której używasz:

int fillarr(int arr[])

To rodzaj po prostu cukru syntaktycznego. Naprawdę możesz go zastąpić tym i nadal będzie działać:

int fillarr(int* arr)

W tym samym sensie to, co chcesz zwrócić z funkcji, to tak naprawdę wskaźnik do pierwszego elementu w tablicy:

int* fillarr(int arr[])

I nadal będziesz mógł używać go tak jak normalnej tablicy:

int main()
{
  int y[10];
  int *a = fillarr(y);
  cout << a[0] << endl;
}
Brent pisze kod
źródło
45
Aby wyjaśnić, ta „klasyczna instrukcja w języku C ++” jest fałszywa; tablice nie są wskaźnikami.
GManNickG
25
pamiętajcie zasadę [i] == * (a + i)
seand
8
@Brent Nash, nie. tablica to tablica. Wskaźnik do początku tablicy jest wskaźnikiem. Zdarza się, że kompilator ma cukier składniowy, który w niektórych sytuacjach wykonuje tłumaczenie. arrayi &arraysą zamienne w wielu przypadkach.
Carl Norum,
20
@Brent: Nie. Tablica jest własnym typem, nie jest specjalnym wskaźnikiem. Typ aIN int a[10]jest int[10]. Można powiedzieć, że tablice „rozpadają się” na wskaźniki do ich pierwszego elementu. (Jest to niejawna konwersja tablic na wskaźniki). Wtedy twoja odpowiedź byłaby zgodna z moimi. Jeśli edytujesz swoją odpowiedź, aby rozróżnić tablice, konwersję tablic na wskaźniki i wskaźniki, usunę moją odpowiedź, ponieważ będą miały te same podstawowe informacje, a ty będziesz pierwszy.
GManNickG
8
@seand pamiętaj o regule a [i] == * (a + sizeof (a) * i)
Amir
114

Funkcje C ++ nie mogą zwracać tablic typu C według wartości. Najbliższą rzeczą jest zwrócenie wskaźnika. Ponadto typ tablicy na liście argumentów jest po prostu konwertowany na wskaźnik.

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

Możesz to poprawić, korzystając z odwołań do tablicy argumentu i return, co zapobiega rozpadowi:

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

W przypadku Boost lub C ++ 11 przekazywanie przez odniesienie jest tylko opcjonalne, a składnia jest mniej wymagająca:

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

arraySzablon po prostu generuje structzawierający tablicę C-style, dzięki czemu można zastosować semantykę obiektowych jeszcze zachowują pierwotną prostotę tablicy użytkownika.

Potatoswatter
źródło
4
+1 za podanie przykładu przekazywania tablicy przez referencję. Ale mylisz się, ponieważ nie możesz zwrócić tablicy przez referencję. Najprostsza składnia osiągnąć to za pomocą typedef: typedef int array[5]; array& foo();Ale ty nawet nie trzeba typedef jeśli zależy Ci napisać to: int (&foo())[5] { static int a[5] = {}; return a; }, przykład w pytaniu będzie: int (&foo( int (&a)[5] ))[5] { return a; }. Proste, prawda?
David Rodríguez - dribeas
@David: dzięki, otrzymałem błędne wrażenie z komunikatu Comeau, error: function returning array is not allowedktóry pojawia się, jeśli pominiesz zewnętrzne pareny w składni nietypowej. Na szczęście dzisiaj sprawdziłem zasadę prawa-lewa dla innego pytania i udało mi się skonstruować właściwą rzecz… po tym, jak powiedziałeś, że to możliwe… zanim zobaczyłeś, że podałeś kod: vP.
Potatoswatter
1
Odpowiedź chubsdada zawiera poprawny cytat ze standardu: nie możesz zwrócić tablicy, ale możesz zwrócić referencję lub wskaźnik do tablicy. Tablic nie można kopiować (jako typu) i jako takie nie można ich zwrócić - co implikowałoby kopię - a gdy taka składnia jest obecna, kompilator przekształci argument na wskaźnik.
David Rodríguez - dribeas
3
@David: Tak się dzieje. Ta strona będzie dziwnie długa. Nigdy tak wiele osób nie napisało dobrowolnie tylu trywialnych funkcji zwracających tablicę w jednym miejscu.
Potatoswatter
@Patatoswatter Jestem nowy w cpp. Czy możesz szczegółowo wyjaśnić fragment drugiego kodu? Nie jestem w stanie rozbić go na części ze względu na zrozumienie.
KPMG
23

W C ++ 11 możesz wrócić std::array.

#include <array>
using namespace std;

array<int, 5> fillarr(int arr[])
{
    array<int, 5> arr2;
    for(int i=0; i<5; ++i) {
        arr2[i]=arr[i]*2;
    }
    return arr2;
}
cubuspl42
źródło
2
Cytując OP:(...) you can consider the array returned arr2, totally another array (...)
cubuspl42
22

8,3,5 USD / 8 stanów

„Funkcje nie powinny mieć zwracanej tablicy typów lub funkcji, chociaż mogą mieć zwracany wskaźnik typu lub odwołanie do takich rzeczy. Nie będzie tablic funkcji, chociaż mogą istnieć tablice wskaźników funkcji.”

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);
}
Chubsdad
źródło
7
Druga funkcja zwraca wskaźnik do int, a nie do tablicy.
GManNickG
ponownie, po co zwracać typ, gdy rzeczywista tablica jest aktualizowana w funkcji? Czy to kwestia najlepszych praktyk?
Dan
14

odpowiedź może nieco zależeć od tego, jak zamierzasz korzystać z tej funkcji. Dla najprostszej odpowiedzi, zdecydujmy, że zamiast tablicy, naprawdę chcesz wektor. Wektory są ładne, ponieważ wygląd całego świata jest nudny, zwykłe wartości, które można przechowywać w regularnych wskaźnikach. Przyjrzymy się innym opcjom i dlaczego chcesz je później:

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

To zrobi dokładnie to, czego oczekujesz. Zaletą jest tostd::vector dba się o to, aby wszystko było traktowane w sposób czysty. Minusem jest to, że kopiuje to bardzo dużą ilość danych, jeśli twoja tablica jest duża. W rzeczywistości kopiuje każdy element tablicy dwukrotnie. najpierw kopiuje wektor, aby funkcja mogła go użyć jako parametru. następnie kopiuje go ponownie, aby zwrócić go dzwoniącemu. Jeśli potrafisz samodzielnie zarządzać wektorem, możesz robić rzeczy o wiele łatwiej. (może skopiować go po raz trzeci, jeśli dzwoniący musi zapisać go w jakiejś zmiennej, aby wykonać więcej obliczeń)

Wygląda na to, że tak naprawdę próbujesz wypełnić tylko kolekcję. jeśli nie masz konkretnego powodu, aby zwrócić nową instancję kolekcji, nie rób tego. możemy to zrobić w ten sposób

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

w ten sposób otrzymujesz odwołanie do tablicy przekazanej do funkcji, a nie jej prywatną kopię. wszelkie zmiany dokonane w parametrze są widoczne dla dzwoniącego. Możesz zwrócić odwołanie, jeśli chcesz, ale to nie jest naprawdę świetny pomysł, ponieważ sugeruje, że dostajesz coś innego niż to, co przekazałeś.

Jeśli naprawdę potrzebujesz nowej instancji kolekcji, ale chcesz uniknąć umieszczenia jej na stosie (i całego związanego z tym kopiowania), musisz utworzyć umowę dotyczącą sposobu obsługi tej instancji. najprostszym sposobem na to jest użycie inteligentnego wskaźnika, który utrzymuje referencyjną instancję tak długo, jak długo ktoś ją trzyma. Znika czysto, jeśli wykracza poza zakres. Tak by to wyglądało.

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

W przeważającej części za pomocą *myArr działa identycznie jak zwykły wektor waniliowy. Ten przykład modyfikuje również listę parametrów poprzez dodanie constsłowa kluczowego. Teraz otrzymujesz referencję bez kopiowania, ale nie możesz jej modyfikować, więc osoba dzwoniąca wie, że będzie taka sama, jak zanim funkcja do niej dotarła.

Wszystko to jest spuchnięte, ale idiomatyczne c ++ rzadko działa z kolekcjami jako całością. Zwykle będziesz używać iteratorów w tych kolekcjach. wyglądałoby to mniej więcej tak

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

Używanie go wygląda trochę dziwnie, jeśli nie jesteś przyzwyczajony do tego stylu.

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

foo teraz „wskazuje” na początek zmodyfikowanego arr .

Naprawdę fajne jest to, że działa równie dobrze na wektorze, jak na zwykłych tablicach C i wielu innych typach kolekcji, na przykład

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

Które teraz wygląda okropnie jak zwykłe przykłady wskaźników podane w innym miejscu tego pytania.

SingleNegationElimination
źródło
Składnia jest niepoprawna, &symbol musi pojawić się po typie:void fillarr(std::vector<int> & arr)
David Rodríguez - dribeas
9

To:

int fillarr(int arr[])

jest traktowany tak samo jak:

int fillarr(int *arr)

Teraz, jeśli naprawdę chcesz zwrócić tablicę, możesz zmienić tę linię na

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

Tak naprawdę to nie zwraca tablicy. zwracasz wskaźnik na początek adresu tablicy.

Pamiętaj jednak, że kiedy przekazujesz tablicę, przekazujesz tylko wskaźnik. Więc kiedy modyfikujesz dane tablicy, tak naprawdę modyfikujesz dane, na które wskazuje wskaźnik. Dlatego zanim przejdziesz do tablicy, musisz zdać sobie sprawę, że masz już na zewnątrz zmodyfikowany wynik.

na przykład

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

Sugeruję, abyś mógł rozważyć umieszczenie długości w swojej funkcji fillarr w ten sposób.

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

W ten sposób możesz użyć długości do wypełnienia tablicy do jej długości bez względu na to, co to jest.

Aby właściwie go używać poprawnie. Zrób coś takiego:

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.

Jeśli wszystko, co chcesz zrobić, to ustawić tablicę na niektóre wartości domyślne, rozważ użycie wbudowanej funkcji memset.

coś takiego: memset ((int *) & arr, 5, sizeof (int));

Chociaż jestem na ten temat. Mówisz, że używasz C ++. Zobacz wektory stl. Twój kod prawdopodobnie będzie bardziej niezawodny.

Istnieje wiele samouczków. Oto jeden, który daje wyobrażenie o tym, jak z nich korzystać. http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html

Matt
źródło
Wykorzystanie std::copyponad memset, jest bezpieczniejsze i łatwiejsze. (I tak samo szybko, jeśli nie szybciej.)
GManNickG
5

aby zwrócić tablicę z funkcji, zdefiniujmy tę tablicę w strukturze; Wygląda to mniej więcej tak

struct Marks{
   int list[5];
}

Teraz stwórzmy zmienne o strukturze typu.

typedef struct Marks marks;
marks marks_list;

Możemy przekazać tablicę do funkcji w następujący sposób i przypisać jej wartość:

void setMarks(int marks_array[]){
   for(int i=0;i<sizeof(marks_array)/sizeof(int);i++)
       marks_list.list[i]=marks_array[i];
}

Możemy również zwrócić tablicę. Aby zwrócić tablicę, zwracany typ funkcji powinien być typu struktury, tj. Znaczników. Jest tak, ponieważ w rzeczywistości przekazujemy strukturę zawierającą tablicę. Tak więc końcowy kod może wyglądać tak.

marks getMarks(){
 return marks_list;
}
Sandeep
źródło
5

To dość stare pytanie, ale zamierzam włożyć moje 2 centy, ponieważ jest wiele odpowiedzi, ale żadne nie pokazuje wszystkich możliwych metod w jasny i zwięzły sposób (nie jestem pewien co do zwięzłego fragmentu, ponieważ otrzymałem bit poza kontrolą. TL; DR 😉).

Zakładam, że OP chciał zwrócić tablicę, która została przekazana bez kopiowania, jako pewien sposób bezpośredniego przekazania tego do programu wywołującego, który zostanie przekazany do innej funkcji, aby kod wyglądał ładniej.

Jednak użycie tablicy takiej jak ta pozwala jej rozpadnąć się na wskaźnik i pozwolić kompilatorowi traktować ją tak tablicę. Może to powodować subtelne błędy, jeśli przejdziesz przez tablicę podobną do, z funkcją oczekującą, że będzie ona miała 5 elementów, ale twój rozmówca faktycznie poda inną liczbę.

Jest kilka sposobów, aby lepiej sobie z tym poradzić. Przekaż std::vectorlub std::array(nie jestem pewien, czy std::arraybyło w 2010 roku, kiedy zadano pytanie). Następnie możesz przekazać obiekt jako odniesienie bez kopiowania / przenoszenia obiektu.

std::array<int, 5>& fillarr(std::array<int, 5>& 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<int>& fillarr(std::vector<int>& arr)
{
    for(auto it = arr.begin(); it != arr.end(); ++it)
    { /* do stuff */ }
    return arr;
}

Jeśli jednak nalegasz na grę tablicami C, użyj szablonu, który zachowa informacje o tym, ile elementów w tablicy.

template <size_t N>
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;
}

Tyle że wygląda brzydko i jest bardzo trudny do odczytania. Teraz używam czegoś, aby pomóc w tym, czego nie było w 2010 roku, którego używam również do wskaźników funkcji:

template <typename T>
using type_t = T;

template <size_t N>
type_t<int(&)[N]> fillarr(type_t<int(&)[N]> 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;
}

Zmienia to typ, w którym można się spodziewać, czyniąc to znacznie bardziej czytelnym. Oczywiście użycie szablonu jest zbędne, jeśli nie zamierzasz używać niczego poza 5 elementami, więc możesz oczywiście go na stałe zapisać:

type_t<int(&)[5]> fillarr(type_t<int(&)[5]> 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;
}

Jak powiedziałem, moja type_t<>sztuczka nie zadziałałaby w chwili, gdy pytanie zostało zadane. Najlepszym, na co wtedy mogłeś mieć nadzieję, było użycie typu w strukturze:

template<typename T>
struct type
{
  typedef T type;
};

typename type<int(&)[5]>::type fillarr(typename type<int(&)[5]>::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;
}

Które zaczyna znów wyglądać dość brzydko, ale przynajmniej jest jeszcze bardziej czytelne, chociaż wtedy typenamemogły być opcjonalne w zależności od kompilatora, w wyniku czego:

type<int(&)[5]>::type fillarr(type<int(&)[5]>::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;
}

I oczywiście mógłbyś podać konkretny typ, zamiast używać mojego pomocnika.

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

Wówczas darmowe funkcje std::begin()i std::end()nie istniały, choć można je było łatwo wdrożyć. Pozwoliłoby to na iterację po tablicy w bezpieczniejszy sposób, ponieważ mają one sens w przypadku tablicy C, ale nie wskaźnika.

Jeśli chodzi o dostęp do tablicy, możesz albo przekazać ją do innej funkcji, która przyjmuje ten sam typ parametru, albo utworzyć alias do niej (co nie miałoby większego sensu, ponieważ masz już oryginał w tym zakresie). Dostęp do odwołania do tablicy jest jak dostęp do oryginalnej tablicy.

void other_function(type_t<int(&)[5]> x) { /* do something else */ }

void fn()
{
    int array[5];
    other_function(fillarr(array));
}

lub

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
}

Podsumowując, najlepiej nie dopuścić do rozpadu tablicy na wskaźnik, jeśli zamierzasz iterować po nim. To po prostu zły pomysł, ponieważ powstrzymuje kompilator przed ochroną przed postrzeleniem się w stopę i utrudnia odczytanie kodu. Zawsze staraj się pomóc kompilatorowi w utrzymaniu typów tak długo, jak to możliwe, chyba że masz bardzo dobry powód, aby tego nie robić.

Edytować

Aha, i dla kompletności, możesz pozwolić, aby zdegradowała się do wskaźnika, ale to oddziela tablicę od liczby elementów, które zawiera. Odbywa się to często w C / C ++ i zwykle jest łagodzone przez przekazywanie liczby elementów w tablicy. Jednak kompilator nie może ci pomóc, jeśli popełnisz błąd i podasz niewłaściwą wartość do liczby elementów.

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

Zamiast przekazać rozmiar, możesz przekazać wskaźnik końca, który wskaże jeden koniec końca tablicy. Jest to przydatne, ponieważ pozwala uzyskać coś, co jest bliższe algorytmom std, które przyjmują wskaźnik początku i końca, ale to, co powrócisz, jest teraz tylko czymś, o czym musisz pamiętać.

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

Alternatywnie możesz udokumentować, że ta funkcja zajmie tylko 5 elementów i masz nadzieję, że użytkownik tej funkcji nie zrobi nic głupiego.

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

Zauważ, że zwracana wartość straciła swój pierwotny typ i jest zdegradowana do wskaźnika. Z tego powodu jesteś teraz sam, aby upewnić się, że nie zamierzasz przekroczyć tablicy.

Możesz przekazać std::pair<int*, int*>, którego możesz użyć na początku i na końcu, i przekazać dalej, ale wtedy naprawdę przestaje wyglądać jak tablica.

std::pair<int*, int*> fillarr(std::pair<int*, int*> 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];
}

lub

void other_function(std::pair<int*, int*> 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])));
}

Zabawne, jest to bardzo podobne do std::initializer_listdziałania (c ++ 11), ale nie działają w tym kontekście.

Adrian
źródło
3

najprostszym sposobem na to jest zwrócenie go przez referencję, nawet jeśli nie napiszesz symbolu „&”, jest on automatycznie zwracany przez referencję

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

  }
nada
źródło
2
int *fillarr(int arr[])

Nadal możesz użyć wyniku jak

int *returned_array = fillarr(some_other_array);
if(returned_array[0] == 3)
    do_important_cool_stuff();
Daniel
źródło
Nie sądzę, by „int [] fillarr ...” był zgodny z prawem. 'Int * fillarr' jest tym, czego byś użył ze względu na równoważność wskaźnika tablicowego.
piątek
1

Jak wyżej wspomniane ścieżki są poprawne. Ale myślę, że jeśli po prostu zwrócimy lokalną zmienną tablicową funkcji, czasami zwraca ona wartości śmieci jako elementy.

w celu uniknięcia tego musiałem dynamicznie utworzyć tablicę i kontynuować. Które jest coś takiego.

int* func()
{
  int* Arr = new int[100];
  return Arr;
}

int main()
{
  int* ArrResult = func();
  cout << ArrResult[0] << " " << ArrResult[1] << endl;
  return 0;
} 



Shehanmark
źródło
0
template<typename T, size_t N>
using ARR_REF = T (&)[N];

template <typename T, size_t N>
ARR_REF<T,N> ArraySizeHelper(ARR_REF<T,N> arr);

#define arraysize(arr) sizeof(ArraySizeHelper(arr))
Nozama
źródło
0

Źródło: https://www.tutorialspoint.com/cplusplus/cpp_return_arrays_from_functions.htm

C ++ nie pozwala na zwrócenie całej tablicy jako argumentu funkcji. Można jednak zwrócić wskaźnik do tablicy, podając jej nazwę bez indeksu.

  1. Jeśli chcesz zwrócić tablicę jednowymiarową z funkcji, musisz zadeklarować funkcję zwracającą wskaźnik, jak w poniższym przykładzie:
int * myFunction()    {
   .
   .
   .
}
  1. C ++ nie zaleca zwracania adresu zmiennej lokalnej poza funkcję, dlatego trzeba zdefiniować zmienną lokalną jako zmienną statyczną.

Stosując te reguły do ​​bieżącego pytania, możemy napisać program w następujący sposób:

# include <iostream>

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

Dane wyjściowe będą:

p[0]=0
p[1]=1
p[2]=2
p[3]=3
p[4]=4
MAQ
źródło
0

a co z:

int (*func())
{
    int *f = new int[10] {1,2,3};

    return f;
}

int fa[10] = { 0 };
auto func2() -> int (*) [10]
{
    return &fa;
}
Alexandr
źródło
0

W rzeczywistości, gdy przekazujesz tablicę wewnątrz funkcji, wskaźnik do oryginalnej tablicy jest przekazywany w parametrze funkcji, a zatem zmiany dokonane w tablicy wewnątrz tej funkcji są faktycznie dokonywane na oryginalnej tablicy.

#include <iostream>

using namespace std;

int* func(int ar[])
{
    for(int i=0;i<100;i++) 
        ar[i]=i;
    int *ptr=ar;
    return ptr;
}


int main() {
    int *p;
    int y[100]={0};    
    p=func(y);

    for(int i=0;i<100;i++) 
        cout<<i<<" : "<<y[i]<<'\n';
}

Uruchom go, a zobaczysz zmiany

Abhishek gaur
źródło
1
Proszę używać poprawnych angielskich sformułowań (zamiast tego zrobisz to) i pomiń puste frazy, takie jak „kolego”.
cześć
Również: „wtedy faktycznie jest przekazywany jako odniesienie” jest błędny. Sama zmienna yjest przekazywana jako jej kopia, ale ponieważ jest wskaźnikiem, będziesz bezpośrednio operować na tablicy. Edytuj swoją odpowiedź.
cześć
stackoverflow.com/questions/5573310/... TL; DR „Zatem obie formy są identyczne”.
cześć
Tak, technicznie jest to tablica, masz rację, ale to, co jest kopiowane, to wskaźnik do tablicy, a nie sama tablica.
cześć
0

Oto pełny przykład tego rodzaju problemu do rozwiązania

#include <bits/stdc++.h>
using namespace std;
int* solve(int brr[],int n)
{
sort(brr,brr+n);
return brr;
}

int main()
{
int n;
cin>>n;
int arr[n];
for(int i=0;i<n;i++)
{
    cin>>arr[i];
}
int *a=solve(arr,n);
for(int i=0;i<n;i++)
{
    cout<<a[i]<<endl;
}

return 0;
}
Shaonsani
źródło
-2

Po prostu zdefiniuj typ [] jako wartość zwracaną, na przykład:

        private string[] functionReturnValueArray(string one, string two)
    {

        string[] x = {one, two};


        x[0] = "a";
        x[1] = "b";

        return x;
    }

. . . wywołanie funkcji:

string[] y;
y = functionReturnValueArray(stringOne, stringTwo)
Ricardo Fercher
źródło
5
To nie jest C ++
Adrian