İşlevdeki dizi döndürme


212

int arr[5]Bir işleve geçirilen bir dizi var fillarr(int arr[]):

int fillarr(int arr[])
{
    for(...);
    return arr;
}
  1. Bu diziyi nasıl iade edebilirim?
  2. Bunu nasıl kullanacağım, bir işaretçiyi geri döndüğümü söyleyerek ona nasıl erişeceğim?

46
kesinlikle bu bağlamda, dizi referansla iletildiği için diziyi döndürmeniz gerekmez, böylece 'arr' içindeki öğelerde yapılan değişiklikler işlevin dışında görülür.
BuggerMe

12
dizinin döndürülmesi zincirleme fonksiyonları için uygundur.
seand

5
Yığında bir dizi oluşturma ve ona bir işaretçi döndürme hatası yapmadığınız sürece.
Ağustos'ta

2
@ismail: Dizi dinamik olarak ayrılmadığı sürece yeni bir dizi döndüremez. Ve eğer durum buysa, kullanın std::vector.
GManNickG

4
@BuggerMe: Diziler edilir değildir (bir çok komik sözdizimi ile bunu talep sürece), referans ile bu geçti kodu, dizi bozunmaktadır ilk elemanı bir işaretçisi ve bu işlev geçirilir. 5Fonksiyon imza derleyici tarafından atılır.
David Rodríguez - dribeas

Yanıtlar:


204

Bu durumda, dizi değişkeniniz arraslında örtülü bir dönüşümle dizideki bellek bloğunun başına bir işaretçi olarak da ele alınabilir. Kullandığınız bu sözdizimi:

int fillarr(int arr[])

Bir çeşit sözdizimsel şekerdir. Gerçekten bununla değiştirebilirsiniz ve yine de işe yarayacaktır:

int fillarr(int* arr)

Aynı anlamda, işlevinizden geri dönmek istediğiniz şey aslında dizideki ilk öğeye bir işaretçi:

int* fillarr(int arr[])

Ve yine de normal bir dizi gibi kullanabilirsiniz:

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

45
Açıklığa kavuşturmak gerekirse, bu "klasik C ++ ifadesi" yanlıştır; diziler işaretçi değildir.
GManNickG

25
a [i] == * (a + i) kuralını
hatırlayın

8
@Brent Nash, hayır. bir dizi bir dizidir. Dizinin başlangıcına bir işaretçi bir işaretçidir. Derleyici bazı durumlarda sizin için çeviriyi yapan sözdizimsel şekere sahip olur. arrayve &arraybirçok durumda değiştirilebilir.
Carl Norum

20
@Brent: Hayır. Bir dizi kendi tipidir, özel bir işaretçi türü değildir. Tipi ain int a[10]olduğunu int[10]. Söyleyebileceğiniz şey, dizilerin ilk öğelerine işaret eden "bozunması" dır. (Bu, örtük bir dizi-işaretçi dönüşümüdür.) O zaman cevabınız benim yaptığım çizgiler boyunca gider. Diziler, dizi-işaretçi dönüşümü ve işaretçiler arasında ayrım yapmak için yanıtınızı düzenlerseniz, aynı temel bilgilere sahip olacağından ve siz ilk sırada olduğunuzdan yanıtımı silerim.
GManNickG

8
@ ve hatırlayın a [i] == * (a + sizeof (a) * i) kuralı
Amir

114

C ++ işlevleri C stili dizileri değere göre döndüremez. En yakın şey bir işaretçi döndürmektir. Ayrıca, bağımsız değişken listesindeki bir dizi türü basitçe bir işaretçiye dönüştürülür.

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

Bağımsız değişken ve dönüş için bir dizi başvurusu kullanarak bunu geliştirebilirsiniz.

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

Boost veya C ++ 11 ile, doğrudan referans yalnızca isteğe bağlıdır ve sözdizimi daha az zihin büker:

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

arrayŞablon sadece üretir structnesne yönelimli anlambilim uygulamak henüz dizinin orijinal basitlik korumak, böylece içeren bir C-tarzı dizi.


4
Bir dizinin referans olarak nasıl iletilebileceğine ilişkin bir örnek vermek için +1 Ancak, bir diziyi başvuru ile döndüremeyeceğiniz için yanılıyorsunuz. En basit sözdizimi, bir typedef kullanmaktır ulaşmak için: typedef int array[5]; array& foo();Ama bunu yazmak ister eğer hatta typedef gerekmez: int (&foo())[5] { static int a[5] = {}; return a; }söz konusu örnek olacaktır: int (&foo( int (&a)[5] ))[5] { return a; }. Basit, değil mi?
David Rodríguez - dribeas

@David: teşekkürler, typea error: function returning array is not allowedolmayan sözdiziminde dış parantezleri dışarıda bırakırsanız oluşan Comeau mesajından yanlış ifadeyi aldım . Neyse ki, bugün başka bir soru için sağ-sol kuralı gözden geçirdim ve doğru olanı kurmayı başardım… mümkün olduğunu söyledikten sonra… vP kodunu verdiğinizi görmeden önce.
Potatoswatter

1
Chubsdad'ın cevabı standarttan doğru alıntıya sahiptir: bir dizi döndüremezsiniz, ancak bir diziye bir başvuru veya işaretçi döndürebilirsiniz. Diziler kopyalanamaz (bir tür olarak) ve bu nedenle, bir kopya anlamına gelen geri döndürülemezler ve bu sözdizimi mevcut olduğunda derleyici, argümanı bir işaretçiye dönüştürür.
David Rodríguez - dribeas

3
@David: Öyle. Bu sayfa tuhaf bir şekilde uzuyor. Asla bu kadar çok insan gönüllü bir şekilde bir dizi bir dizide dönen çok önemsiz fonksiyonlar yazmayın.
Potatoswatter

@Potatoswatter Ben cpp için yeniyim, 2. kod snippet'ini detaylı olarak açıklayabilir misiniz? Anlamak adına onu parçalara ayıramıyorum.
KPMG

23

C ++ 11'de geri dönebilirsiniz 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;
}

2
(...) you can consider the array returned arr2, totally another array (...)
OP'den

22

8.3.5 $ / 8 eyalet-

"İşlevlerin dönüş tipi tür dizisi veya işlevi bulunmamalı, ancak dönüş türü tür işaretçisi veya bu türden bir başvuruya sahip olabilirler. İşlevlere işaretçi dizileri olsa da işlev dizisi bulunmayacaktır."

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

7
İkinci işleviniz intbir diziye değil, bir işaretçiye bir işaretçi döndürür .
GManNickG

yine, gerçek dizi fonksiyonun içinde güncellendiğinde türü neden döndürürsünüz? En iyi uygulama meselesi mi?
Dan

14

cevap, bu işlevi nasıl kullanmayı planladığınıza bağlı olabilir. En basit cevap için, bir dizi yerine, gerçekten istediğiniz şeyin bir vektör olduğuna karar verelim. Vektörler güzel çünkü düzenli işaretçilerde saklayabileceğiniz sıkıcı, sıradan değerler gibi tüm dünyaya bakış. Diğer seçeneklere ve daha sonra bunları neden istediğinize bakacağız:

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

Bu tam olarak yapmasını beklediğiniz şeyi yapacaktır. Tersi, std::vectorher şeyin temiz bir şekilde ele alındığından emin olmaktır. dezavantajı, diziniz büyükse, çok büyük miktarda veri kopyalamasıdır. Aslında, dizinin her öğesini iki kez kopyalar. önce fonksiyonun parametre olarak kullanabilmesi için vektörü kopyalar. sonra arayana geri döndürmek için tekrar kopyalar. Vektörü kendiniz yönetebiliyorsanız, işleri biraz daha kolay yapabilirsiniz. (arayanın daha fazla hesaplama yapmak için bir değişkente saklaması gerekirse üçüncü kez kopyalayabilir)

Gerçekten yapmaya çalıştığınız şey sadece bir koleksiyonu doldurmak gibi görünüyor. koleksiyonun yeni bir örneğini döndürmek için belirli bir nedeniniz yoksa yapma. böyle yapabiliriz

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

bu şekilde özel bir kopyası değil, işleve iletilen diziye bir başvuru alırsınız. parametrede yaptığınız tüm değişiklikler arayan tarafından görülür. İsterseniz buna bir referans döndürebilirsiniz, ancak bu gerçekten harika bir fikir değildir, çünkü geçtiğinizden farklı bir şey aldığınızı ima eder.

Koleksiyonun gerçekten yeni bir örneğine ihtiyacınız varsa, ancak yığında (ve beraberinde gelen tüm kopyalamayı) kullanmaktan kaçınmak istiyorsanız, bu örneğin nasıl işlendiğine ilişkin bir tür sözleşme oluşturmanız gerekir. bunu yapmanın en kolay yolu, başvurulan örneği üzerinde durduğu sürece tutan akıllı bir işaretçi kullanmaktır. Kapsam dışına çıkarsa temiz bir şekilde gider. Bu böyle görünecektir.

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

Çoğunlukla, kullanmak *myArrdüz bir vanilya vektörü ile aynı şekilde çalışır. Bu örnek ayrıca constanahtar kelime ekleyerek parametre listesini değiştirir . Şimdi kopyalamadan bir referans alırsınız, ancak değiştiremezsiniz, böylece arayan, işlevin ulaşmadan önceki ile aynı olacağını bilir.

Bütün bunlar harika, ama deyimsel c ++ nadiren bir bütün olarak koleksiyonlarla çalışır. Daha normal olarak, bu koleksiyonlar üzerinde yineleyiciler kullanacaksınız. bu daha çok şuna benzer

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

Bu stili görmeye alışkın değilseniz, kullanmak biraz garip görünüyor.

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

foo şimdi 'değiştirilmişin başlangıcını' gösteriyor arr.

Bu konuda gerçekten güzel olan şey, düz C dizilerinde ve diğer birçok koleksiyon türünde olduğu gibi vektör üzerinde eşit derecede iyi çalışmasıdır.

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

Şimdi bu sorunun başka bir yerinde verilen düz işaretçi örneklerine çok benziyor.


Sözdizimi yanlış, &sembol şu türden sonra görünmelidir:void fillarr(std::vector<int> & arr)
David Rodríguez - dribeas

9

Bu:

int fillarr(int arr[])

aslında aşağıdakilerle aynı şekilde ele alınır:

int fillarr(int *arr)

Şimdi gerçekten bir dizi döndürmek istiyorsanız o satırı şu şekilde değiştirebilirsiniz:

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

Gerçekten bir dizi döndürmüyor. dizi adresinin başına bir işaretçi döndürüyorsunuz.

Ancak diziyi geçtiğinizde, yalnızca bir işaretçiyi geçtiğinizi unutmayın. Dizi verisini değiştirdiğinizde, aslında işaretçinin işaret ettiği verileri değiştirirsiniz. Bu nedenle, diziyi geçmeden önce, değiştirilmiş sonucun dışında zaten bulunduğunuzu fark etmelisiniz.

Örneğin

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 fonksiyonunuza böyle bir uzunluk koymayı düşünebilirsiniz.

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

Bu şekilde, uzunluğu ne olursa olsun diziyi uzunluğuna doldurmak için uzunluk kullanabilirsiniz.

Aslında düzgün kullanmak için. Bunun gibi bir şey yapın:

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.

Yapmak istediğiniz tek şey diziyi bazı varsayılan değerlere ayarlamaksa, yerleşik memset işlevini kullanmayı düşünün.

şuna benzer: memset ((int *) ve arr, 5, sizeof (int));

Ben konuyla ilgili olsa da. C ++ kullandığınızı söylüyorsunuz. Stl vektörlerini kullanmaya bir göz atın. Kodunuzun daha sağlam olması muhtemeldir.

Çok sayıda öğretici var. İşte size bunları nasıl kullanacağınız hakkında bir fikir veren. http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html


Kullanım std::copyüzerinde memset, daha güvenli ve daha kolay. (Ve daha hızlı olmasa bile hızlı.)
GManNickG

5

bir diziyi işlevden döndürmek için, o diziyi bir yapıda tanımlayalım; Yani böyle bir şey görünüyor

struct Marks{
   int list[5];
}

Şimdi tür yapısının değişkenlerini yaratalım.

typedef struct Marks marks;
marks marks_list;

Diziyi bir işleve şu şekilde geçirebilir ve ona bir değer atayabiliriz:

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

Diziyi de döndürebiliriz. Diziyi döndürmek için, işlevin dönüş türü yapı tipi yani işaretler olmalıdır. Çünkü gerçekte diziyi içeren yapıyı geçiyoruz. Yani son kod böyle görünebilir.

marks getMarks(){
 return marks_list;
}

5

Bu oldukça eski bir soru, ama çok fazla cevap olduğu için 2 sentime koyacağım, ancak hiçbiri tüm olası yöntemleri net ve özlü bir şekilde göstermiyor (özlü bitden emin değilim, çünkü bu bir biraz elden. TL; DR 😉).

Ben OP doğrudan kodun daha güzel görünmesi için başka bir işleve geçirilmesi için arayan bu doğrudan geçme bazı araçlar olarak kopyalamadan geçirilen dizi dönmek istediğini varsayıyorum.

Bununla birlikte, böyle bir dizi kullanmak, bir işaretçiye bozunmasına ve derleyicinin bir dizi gibi davranmasına izin vermektir . Bunun gibi bir diziye geçerseniz işlev 5 öğeye sahip olmasını beklerken küçük hatalara neden olabilir, ancak aracınız aslında başka bir sayıdan geçer.

Bunu daha iyi ele almanın birkaç yolu var. Birstd::vector ya dastd::array ( std::arraysoru sorulduğunda 2010 yılında olup olmadığından emin değilim ). Daha sonra nesneyi kopyalama / taşıma olmadan nesneyi başvuru olarak iletebilirsiniz.

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

Bununla birlikte, C dizileriyle oynamakta ısrar ediyorsanız, dizideki kaç öğenin bilgilerini tutacak bir şablon kullanın.

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

Dışında, bu çirkin görünüyor ve okumak çok zor. Şimdi 2010'da olmayanlara yardımcı olmak için işlev işaretçileri için de kullandığım bir şey kullanıyorum:

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

Bu, türün olmasını beklediği yerde hareket eder ve bu kadar ileri gider daha okunabilir. Tabii ki, 5 element dışında bir şey kullanmayacaksanız bir şablon kullanmak gereksizdir, bu yüzden elbette zor kodlayabilirsiniz:

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

Dediğim gibi benim type_t<> bu soru sorulduğunda hilem işe yaramazdı. O zamanlar için umabileceğiniz en iyi şey bir yapıda bir tür kullanmaktı:

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

Bu yine oldukça çirkin görünmeye başlar, ancak en azından yine de daha okunabilir typename , derleyiciye bağlı olarak isteğe bağlı olabilir, sonuç:

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

Ve sonra elbette yardımcımı kullanmak yerine belirli bir tür belirtebilirdiniz.

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

O zamanlar serbest fonksiyonlar std::begin() ve std::end()mevcut değildi, ancak kolayca uygulanabilirdi. Bu, bir C dizisinde anlamlı oldukları, ancak bir işaretçi olmadığı için dizi üzerinde daha güvenli bir şekilde yinelemeye izin verirdi.

Diziye erişmeye gelince, onu aynı parametre türünü alan başka bir işleve geçirebilir veya diziye bir takma ad (bu kapsamda orijinaline sahip olduğunuz kadar anlamlı olmaz) olabilir. Dizi referansına erişmek, orijinal diziye erişmek gibidir.

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

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

veya

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
}

Özetlemek gerekirse, eğer bir dizi üzerinde yineleme yapmak istiyorsanız, bir dizi işaretçisinin bir işaretçiye dönüşmesine izin vermemek en iyisidir. Bu sadece kötü bir fikir çünkü derleyicinin sizi ayağınızdan çekmekten korumasını ve kodunuzu okumayı zorlaştırıyor. Bunu yapmamanız için çok iyi bir nedeniniz yoksa türleri mümkün olduğunca uzun süre tutarak derleyicinin size yardımcı olmasına çalışın.

Düzenle

Oh, ve bütünlük için, bir işaretçiye indirgenmesine izin verebilirsiniz, ancak bu diziyi sahip olduğu öğe sayısından ayırır. Bu C / C ++ 'da çok yapılır ve genellikle dizideki elemanların sayısı geçirilerek hafifletilir. Ancak, bir hata yaparsanız ve öğe sayısına yanlış değer iletirseniz derleyici size yardımcı olamaz.

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

Boyutu iletmek yerine, dizinizin sonunu geçecek bir bitiş işaretçisini iletebilirsiniz. Bu, başlangıç ​​ve bitiş işaretçisini alan std algoritmalarına daha yakın olan bir şey için yararlı olduğu için yararlıdır, ancak geri döndüğünüz şey artık yalnızca hatırlamanız gereken bir şeydir.

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

Alternatif olarak, bu işlevin yalnızca 5 öğe alacağını belgeleyebilir ve işlevinizin kullanıcısının aptalca bir şey yapmamasını umabilirsiniz.

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

Dönüş değerinin orijinal türünü kaybettiğini ve bir işaretçiye indirildiğini unutmayın. Bu nedenle, diziyi aşmayacağınızdan emin olmak için artık kendi başınızasınız.

std::pair<int*, int*>Başlamak ve bitirmek için kullanabileceğiniz bir a geçebilirsiniz ve bunu geçebilirsiniz, ancak sonra gerçekten bir dizi gibi görünmeyi bırakır.

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

veya

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

Yeterince komik, bu nasıl std::initializer_listçalıştığına çok benziyor (c ++ 11), ancak bu bağlamda çalışmıyorlar.


3

Bunu yapmanın en basit yolu, '&' sembolünü yazmasanız bile referans ile geri döndürmektir.

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

  }

2
int *fillarr(int arr[])

Sonucu şu şekilde kullanabilirsiniz:

int *returned_array = fillarr(some_other_array);
if(returned_array[0] == 3)
    do_important_cool_stuff();

'İnt [] fillarr ...' nin yasal olduğunu düşünmüyorum. 'İnt * fillarr', dizi-işaretçi denkliği nedeniyle kullanacağınız şeydir.
seand

1

Yukarıda belirtildiği gibi yollar doğrudur. Ama biz sadece bir fonksiyonun yerel dizi değişkeni döndürürsek bazen öğeleri olarak çöp değerleri döndürür düşünüyorum.

sırayla dinamik olarak dizi oluşturmak ve devam etmek zorunda önlemek için. Bu böyle bir şey.

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

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




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))


0

Kaynak: https://www.tutorialspoint.com/cplusplus/cpp_return_arrays_from_functions.htm

C ++, bir dizinin tamamını işleve bağımsız değişken olarak döndürmeye izin vermez. Ancak, dizinin adını dizin olmadan belirterek diziye bir işaretçi döndürebilirsiniz.

  1. Bir işlevden tek boyutlu bir dizi döndürmek istiyorsanız, aşağıdaki örnekte olduğu gibi işaretçiyi döndüren bir işlevi bildirmeniz gerekir:
int * myFunction()    {
   .
   .
   .
}
  1. C ++, yerel bir değişkenin adresini işlevin dışına döndürmeyi savunmaz, böylece yerel değişkeni statik değişken olarak tanımlamanız gerekir.

Bu soruyu mevcut soruya uygulayarak programı aşağıdaki gibi yazabiliriz:

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

Çıktı:

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

0

ve ne hakkında:

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

    return f;
}

int fa[10] = { 0 };
auto func2() -> int (*) [10]
{
    return &fa;
}

0

Aslında bir fonksiyonun içindeki bir diziyi ilettiğinizde, orijinal diziye işaretçi fonksiyon parametresinde iletilir ve böylece o fonksiyonun içindeki dizide yapılan değişiklikler aslında orijinal dizide yapılır.

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

Çalıştırın ve değişiklikleri göreceksiniz


1
Lütfen uygun ingilizce ifadeler kullanın (bunun yerine u olacaksınız) ve "arkadaş" gibi boş ifadeleri atlayın.
hellow

Ayrıca: "o zaman aslında bir referans olarak geçirilir" yanlıştır. Değişkenin ykendisi bir kopyası olarak geçirilir, ancak bir işaretçi olduğundan, doğrudan dizi üzerinde çalışacaksınız. Lütfen cevabınızı düzenleyin.
hellow

stackoverflow.com/questions/5573310/… TL; DR "Böylece iki form aynıdır."
hellow

Evet, teknik olarak bir dizidir, haklısınız, ancak kopyalanan şey dizinin kendisini değil dizinin bir göstergesidir.
hellow

0

İşte çözmek için bu tür bir sorunun tam bir örneği

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

-2

Bir tür [] değerini dönüş değeri olarak tanımlayın, örneğin:

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

        string[] x = {one, two};


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

        return x;
    }

. . . fonksiyon çağrısı:

string[] y;
y = functionReturnValueArray(stringOne, stringTwo)

5
Bu C ++ değil
Adrian
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.