किसी फ़ंक्शन में सरणी लौटें


212

मेरे पास एक एरे है int arr[5]जिसे एक फंक्शन में पास किया जाता है fillarr(int arr[]):

int fillarr(int arr[])
{
    for(...);
    return arr;
}
  1. मैं उस सरणी को कैसे वापस कर सकता हूं?
  2. मैं इसका उपयोग कैसे करूंगा, कहते हैं कि मैंने एक पॉइंटर लौटाया है मैं इसे कैसे एक्सेस करने जा रहा हूं?

46
इस संदर्भ में कड़ाई से बोलते हुए आपको सरणी को वापस करने की आवश्यकता नहीं है क्योंकि सरणी को संदर्भ द्वारा पारित किया जाता है इसलिए 'गिरफ्तार' के तत्वों में कोई भी परिवर्तन फ़ंक्शन के बाहर देखा जाएगा।
BuggerMe

12
सरणी वापस करना कार्यों को चलाने के लिए सुविधाजनक है।
सीड

5
जब तक आप स्टैक पर एक सरणी बनाने और उसमें एक पॉइंटर वापस करने की गलती नहीं कर रहे हैं।
detly

2
@ismail: यह तब तक एक नया सरणी नहीं लौटा सकता, जब तक कि उस सरणी को गतिशील रूप से आवंटित नहीं किया गया था। और अगर ऐसा है, तो उपयोग करें std::vector
GManNickG

4
@BuggerMe: Arrays को संदर्भ द्वारा पारित नहीं किया जाता है (जब तक कि आप इसे बहुत मजेदार सिंटैक्स के साथ अनुरोध नहीं करते हैं), कोड में, सरणी पहले तत्व में एक संकेतक में बदल जाती है और यह फ़ंक्शन को पास कर देता है। 5समारोह हस्ताक्षर में संकलक द्वारा खारिज कर दिया गया है।
डेविड रॉड्रिग्ज - ड्रिबीज

जवाबों:


204

इस मामले में, आपके सरणी चर 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;
}

45
स्पष्ट करने के लिए, कि "क्लासिक सी ++ बयान" गलत है; सरणियाँ संकेत नहीं हैं।
GManNickG

25
एक [i] == * (a + i) नियम याद रखें
सीज़न

8
@ बर्ट नैश, नहीं। एक सरणी एक सरणी है। सरणी की शुरुआत के लिए एक सूचक एक सूचक है। यह सिर्फ ऐसा होता है कि संकलक में कुछ वाक्यगत चीनी होती है जो कुछ स्थितियों में आपके लिए अनुवाद करती है। arrayऔर &arrayबहुत से मामलों में विनिमेय हैं।
कार्ल नॉरम

20
@ बेंट: नहीं। एक सरणी यह ​​स्वयं का प्रकार है, यह एक विशेष प्रकार का सूचक नहीं है। के प्रकार aमें int a[10]है int[10]। क्या आप कह सकते हैं कि सरणियों को "क्षय" उनके पहले तत्व को इंगित करता है। (यह एक अंतर्निहित सरणी-से-पॉइंटर रूपांतरण है।) तब आपका जवाब मेरे द्वारा की जाने वाली लाइनों के साथ होगा। यदि आप सरणियों, सरणी-से-सूचक रूपांतरण और संकेत के बीच अंतर करने के लिए अपना उत्तर संपादित करते हैं, तो मैं अपना उत्तर हटा दूंगा क्योंकि उनके पास एक ही मूल जानकारी होगी और आप पहले थे।
GMANNICKG

8
@seand को एक [i] == * (a + sizeof (a) * i) नियम याद है
Amir

114

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

बूस्ट या C ++ 11 के साथ, पास-दर-संदर्भ केवल वैकल्पिक है और वाक्य-विन्यास कम दिमाग वाला है:

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

arrayटेम्पलेट बस एक उत्पन्न करता है structताकि आप वस्तु उन्मुख अर्थ विज्ञान लागू अभी तक सरणी के मूल सादगी को बनाए रखने कर सकते हैं, जिसमें एक सी शैली सरणी।


4
संदर्भ द्वारा किसी सरणी को कैसे पारित किया जा सकता है, इसका उदाहरण देने के लिए +1। लेकिन आप इसमें गलत हैं कि आप किसी सरणी को संदर्भ द्वारा वापस नहीं कर सकते। इसे प्राप्त करने के लिए सबसे सरल वाक्यविन्यास एक टंकण का उपयोग करके है: typedef int array[5]; array& foo();लेकिन अगर आपको यह लिखने की परवाह है, तो आपको टंकण की आवश्यकता भी नहीं है: int (&foo())[5] { static int a[5] = {}; return a; }प्रश्न में उदाहरण यह होगा int (&foo( int (&a)[5] ))[5] { return a; }:। सरल, है ना?
डेविड रॉड्रिग्ज - drieaseas

@ डेविड: धन्यवाद, मुझे कॉम्यू संदेश से गलतफहमी हुई error: function returning array is not allowedजो तब होता है जब आप गैर-टाइपडिफ सिंटैक्स में बाहरी पार्न्स को छोड़ देते हैं। सौभाग्य से, आज मैंने एक और प्रश्न के लिए दाएं-बाएं नियम की समीक्षा की और सही चीज़ का निर्माण करने में कामयाब रहा ... यह देखने के बाद कि आप यह संभव है ... यह देखने से पहले कि आपने कोड दिया था: vP।
पोटाटोस्वाटर

1
Chubsdad द्वारा दिए गए उत्तर में मानक से सही उद्धरण है: आप किसी सरणी को वापस नहीं कर सकते, लेकिन आप किसी संदर्भ या सूचक को किसी सरणी में वापस कर सकते हैं। Arrays गैर-प्रतिलिपि करने योग्य (एक प्रकार के रूप में) हैं और जैसे कि उन्हें वापस नहीं किया जा सकता है - जो कि एक प्रति है - और जब वह सिंटैक्स मौजूद होगा तो कंपाइलर तर्क को पॉइंटर में बदल देगा।
डेविड रॉड्रिग्ज - dribeas

3
@ डेविड: तो यह करता है। यह पृष्ठ विचित्र रूप से लंबा हो रहा है। कभी भी इतने सारे लोगों ने स्वेच्छा से इतने सारे तुच्छ कार्यों को एक जगह पर नहीं लिखा है।
पोटाटोस्वाटर

@Potatoswatter मैं cpp के लिए नया हूं, क्या आप दूसरे कोड स्निपेट के बारे में विस्तार से बता सकते हैं? मैं इसे समझने के लिए भागों में नहीं तोड़ पा रहा हूँ।
केपीएमजी

23

C ++ 11 में, आप वापस आ सकते हैं 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 (...)
कोटिंग

22

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

7
आपका दूसरा फ़ंक्शन एक पॉइंटर को एक को लौटाता है int, न कि एक सरणी को।
GManNickG

फिर, फ़ंक्शन के अंदर वास्तविक सरणी अपडेट होने पर टाइप क्यों लौटाएं? क्या यह सर्वोत्तम अभ्यास की बात है?
दान

14

आप उस फ़ंक्शन का उपयोग करने की योजना पर थोड़ा सा निर्भर हो सकते हैं। सरलतम उत्तर के लिए, यह तय करने देता है कि एक सरणी के बजाय, आप वास्तव में जो चाहते हैं वह एक वेक्टर है। वेक्टर्स अच्छे हैं क्योंकि सभी दुनिया जैसे कि उबाऊ, सामान्य मूल्यों को आप नियमित पॉइंटर्स में स्टोर कर सकते हैं। हम अन्य विकल्पों को देखेंगे और आप उन्हें बाद में क्यों चाहते हैं:

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

यह वही करेगा जो आप इसे करने की उम्मीद करते हैं। उल्टा यह है कि यह सुनिश्चित करने std::vectorका ख्याल रखता है कि सब कुछ सफाई से संभाला जाए। नकारात्मक पक्ष यह है कि यह डेटा बहुत बड़ी मात्रा में कॉपी करता है, यदि आपका सरणी बड़ा है। वास्तव में यह सरणी के प्रत्येक तत्व को दो बार कॉपी करता है। पहले यह वेक्टर को कॉपी करता है ताकि फ़ंक्शन इसे एक पैरामीटर के रूप में उपयोग कर सके। फिर इसे कॉल करने वाले को वापस करने के लिए इसे फिर से कॉपी करता है। यदि आप स्वयं वेक्टर का प्रबंधन कर सकते हैं, तो आप चीजों को थोड़ा और आसानी से कर सकते हैं। (इसे तीसरी बार कॉपी कर सकते हैं यदि कॉलर को अधिक गणना करने के लिए किसी प्रकार के चर में संग्रहीत करने की आवश्यकता होती है)

ऐसा लगता है कि आप वास्तव में क्या करने की कोशिश कर रहे हैं, बस एक संग्रह को आबाद करना है। यदि आपके पास संग्रह का नया उदाहरण वापस करने का कोई विशिष्ट कारण नहीं है, तो न करें। हम इसे इस तरह से कर सकते हैं

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

इस तरह से आपको फ़ंक्शन के लिए पास की गई सरणी का संदर्भ मिलता है, न कि इसकी एक निजी प्रति। पैरामीटर में आपके द्वारा किए गए किसी भी परिवर्तन को कॉलर द्वारा देखा जाता है। यदि आप चाहते हैं तो आप इसका संदर्भ वापस कर सकते हैं, लेकिन यह वास्तव में एक महान विचार नहीं है, क्योंकि इसका मतलब है कि आप जो कुछ भी पारित किया है उससे कुछ अलग कर रहे हैं।

यदि आपको वास्तव में संग्रह की एक नई आवृत्ति की आवश्यकता है, लेकिन इसे स्टैक पर रखने से बचना चाहते हैं (और सभी कॉपी जो जोर देती है), तो आपको उस उदाहरण को कैसे संभाला जाए, इसके लिए कुछ प्रकार के अनुबंध बनाने की आवश्यकता है। ऐसा करने का सबसे आसान तरीका स्मार्ट पॉइंटर का उपयोग करना है, जो संदर्भित उदाहरण को तब तक रखता है जब तक कोई उस पर पकड़ बना रहा है। यदि यह दायरे से बाहर हो जाता है तो यह साफ हो जाता है। जो इस तरह दिखेगा।

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

अधिकांश भाग के लिए, *myArrएक सादे वेनिला वेक्टर का उपयोग करने के लिए समान रूप से काम करता है। यह उदाहरण constकीवर्ड को जोड़कर पैरामीटर सूची को भी संशोधित करता है । अब आपको इसे कॉपी किए बिना एक संदर्भ मिलता है, लेकिन आप इसे संशोधित नहीं कर सकते हैं, इसलिए फोन करने वाले को पता है कि फ़ंक्शन के पास जाने से पहले यह उसी तरह होगा।

यह सब प्रफुल्लित है, लेकिन मुहावरेदार सी ++ शायद ही कभी पूरी तरह से संग्रह के साथ काम करता है। सामान्य रूप से, आप उन संग्रहों पर पुनरावृत्तियों का उपयोग करेंगे। यह कुछ इस तरह दिखेगा

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

यदि आप इस शैली को देखने के आदी नहीं हैं, तो इसका उपयोग करना थोड़ा अजीब लगता है।

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

फू अब 'संशोधित की शुरुआत' को इंगित करता है arr

इसके बारे में वास्तव में अच्छा है कि यह वेक्टर पर समान रूप से अच्छी तरह से काम करता है जैसे कि सी सी सरणियों और कई अन्य प्रकार के संग्रह, उदाहरण के लिए

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

जो अब इस प्रश्न में कहीं और दिए गए प्लेन पॉइंटर उदाहरणों की तरह एक बहुत ही भयानक लग रहा है।


वाक्यविन्यास गलत है, &प्रतीक को इस प्रकार के बाद दिखाई देना चाहिए:void fillarr(std::vector<int> & arr)
डेविड रोड्रिग्ज़ - dribeas

9

यह:

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

मेरा सुझाव है कि आप इस तरह से अपने भराई समारोह में एक लंबाई पर विचार करना चाहते हो सकता है।

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.

यदि आप सभी करना चाहते हैं, तो सरणी को कुछ डिफ़ॉल्ट मानों पर सेट करें, अंतर्निहित फ़ंक्शन का उपयोग करने पर विचार करें।

कुछ इस तरह: मेमसेट ((इंट *) & अरेस्ट, 5, साइज़ोफ़ (इंट));

हालांकि मैं इस विषय पर हूं। आप कहते हैं कि आप C ++ का उपयोग कर रहे हैं। Stl वैक्टर का उपयोग करने पर एक नज़र है। आपका कोड अधिक मजबूत होने की संभावना है।

बहुत सारे ट्यूटोरियल हैं। यहाँ एक है जो आपको उन्हें कैसे उपयोग करने का एक विचार देता है। http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html


std::copyओवर का उपयोग करें memset, यह सुरक्षित और आसान है। (और उतनी ही तेजी से अगर तेज नहीं है।)
GManNickG

5

किसी फ़ंक्शन से एक सरणी वापस करने के लिए, आइए हम उस सरणी को एक संरचना में परिभाषित करें; तो यह कुछ इस तरह दिखता है

struct Marks{
   int list[5];
}

अब हम टाइप स्ट्रक्चर के वैरिएबल बनाते हैं।

typedef struct Marks marks;
marks marks_list;

हम किसी फ़ंक्शन को निम्न तरीके से पास कर सकते हैं और उसके लिए मान प्रदान कर सकते हैं:

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

हम ऐरे को भी वापस कर सकते हैं। सरणी को वापस करने के लिए, फ़ंक्शन का रिटर्न प्रकार संरचना के प्रकार का होना चाहिए अर्थात निशान। ऐसा इसलिए है क्योंकि वास्तव में हम संरचना को पारित कर रहे हैं जिसमें सरणी शामिल है। तो अंतिम कोड इस तरह दिख सकता है।

marks getMarks(){
 return marks_list;
}

5

यह एक काफी पुराना प्रश्न है, लेकिन मैं अपने 2 सेंट में डालने जा रहा हूं क्योंकि बहुत सारे उत्तर हैं, लेकिन स्पष्ट और संक्षिप्त तरीके से सभी संभव तरीके नहीं दिखा रहे हैं (संक्षिप्त बिट के बारे में निश्चित नहीं है, क्योंकि यह एक बहुत ही अच्छा है। हाथ से थोड़ा बाहर। टीएल; डीआर।)।

मैं यह मान रहा हूं कि ओपी उस सरणी को वापस करना चाहता था जिसे बिना कॉपी किए पास कर दिया गया था क्योंकि इसे सीधे कॉल करने वाले के पास भेजा जा रहा था ताकि कोड लुक को प्रीटियर बनाया जा सके।

हालांकि, इस तरह एक सरणी का उपयोग करने के लिए इसे एक सूचक में क्षय होने देना है और संकलक को एक सरणी की तरह व्यवहार करना है । इसके परिणामस्वरूप सूक्ष्म कीड़े हो सकते हैं यदि आप किसी सरणी में गुजरते हैं, तो फ़ंक्शन के साथ यह अपेक्षा करता है कि इसमें 5 तत्व होंगे, लेकिन आपका कॉलर वास्तव में किसी अन्य नंबर से गुजरता है।

वहाँ कुछ तरीके आप इस बेहतर संभाल कर सकते हैं। पास में std::vectorया std::array(यह निश्चित नहीं है कि std::array2010 के आसपास था जब सवाल पूछा गया था)। फिर आप ऑब्जेक्ट को बिना किसी कॉपी / मूविंग के संदर्भ के रूप में पास कर सकते हैं।

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

हालांकि, यदि आप सी सरणियों के साथ खेलने पर जोर देते हैं, तो एक टेम्पलेट का उपयोग करें जो सरणी में कितने आइटमों की जानकारी रखेगा।

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

सिवाय इसके कि बट बदसूरत दिखता है, और पढ़ने के लिए सुपर कठिन है। मैं अब उस चीज की मदद के लिए कुछ का उपयोग करता हूं जो 2010 में आसपास नहीं थी, जिसे मैं फ़ंक्शन पॉइंटर्स के लिए भी उपयोग करता हूं:

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

इस प्रकार जहां एक यह होने की अपेक्षा करेंगे, इस बनाने चालें दूर अधिक पठनीय। बेशक, एक टेम्पलेट का उपयोग करना बहुत ही अच्छा है यदि आप कुछ और नहीं बल्कि 5 तत्वों का उपयोग करने जा रहे हैं, तो आप इसे कठिन कोड कर सकते हैं:

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

जैसा कि मैंने कहा, मेरी type_t<>चाल उस समय काम नहीं करती थी जब यह प्रश्न पूछा गया था। सबसे अच्छा आप जिस पर वापस जा सकते थे, उसके लिए एक संरचना में एक प्रकार का उपयोग करना था:

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

जो फिर से बहुत बदसूरत दिखना शुरू कर देता है, लेकिन कम से कम अभी भी अधिक पठनीय है, हालांकि typenameवैकल्पिक रूप से वापस हो सकता है, फिर कंपाइलर पर निर्भर करता है, जिसके परिणामस्वरूप:

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

और फिर निश्चित रूप से आप मेरे सहायक का उपयोग करने के बजाय एक विशिष्ट प्रकार निर्दिष्ट कर सकते थे।

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()मौजूद नहीं था, हालांकि आसानी से लागू किया जा सकता था। इसने सरणी पर अधिक सुरक्षित तरीके से पुनरावृत्ति की अनुमति दी होगी क्योंकि वे सी सरणी पर अर्थ रखते हैं, लेकिन सूचक नहीं।

सरणी तक पहुँचने के लिए, आप या तो इसे किसी अन्य फ़ंक्शन में पास कर सकते हैं जो समान पैरामीटर प्रकार लेता है, या इसके लिए एक उपनाम बनाता है (जो कि आपके पास उस दायरे में मूल रूप से पहले से ही बहुत अधिक अर्थ नहीं होगा)। किसी सरणी संदर्भ तक पहुँचना मूल सरणी तक पहुँचने की तरह ही है।

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

संक्षेप में, यदि आप इस पर पुनरावृति करने का इरादा रखते हैं, तो एक सूचक में एक सरणी क्षय की अनुमति नहीं देना सबसे अच्छा है। यह सिर्फ एक बुरा विचार है क्योंकि यह संकलक को पैर में खुद को गोली मारने से बचाने के लिए रखता है और आपके कोड को पढ़ने के लिए कठिन बना देता है। हमेशा कोशिश करें और कंपाइलर की मदद करें जब तक संभव हो तब तक टाइप करके रखें जब तक आपके पास ऐसा न करने का एक बहुत अच्छा कारण न हो।

संपादित करें

ओह, और पूर्णता के लिए, आप इसे एक पॉइंटर को नीचा दिखाने की अनुमति दे सकते हैं, लेकिन यह सरणी को धारण किए गए तत्वों की संख्या से हटाता है। यह सी / सी ++ में बहुत कुछ किया जाता है और आमतौर पर सरणी में तत्वों की संख्या को पारित करके कम किया जाता है। हालांकि, कंपाइलर आपकी मदद नहीं कर सकता है यदि आप गलती करते हैं और तत्वों की संख्या के लिए गलत मान में पास होते हैं।

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

आकार पास करने के बजाय, आप अंतिम पॉइंटर पास कर सकते हैं, जो आपके सरणी के अंत में एक अतीत को इंगित करेगा। यह उपयोगी है क्योंकि यह कुछ के लिए बनाता है जो एसटीडी एल्गोरिदम के करीब है, जो एक शुरुआत और अंत पॉइंटर लेते हैं, लेकिन आप जो वापसी करते हैं वह अब केवल कुछ है जो आपको याद रखना चाहिए।

// 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<int*, int*>कर सकते हैं, जिसे आप शुरू और अंत के लिए उपयोग कर सकते हैं और उस आस-पास से गुजर सकते हैं, लेकिन फिर यह वास्तव में एक सरणी की तरह दिखता है।

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

या

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

काफी मजेदार है, यह बहुत ही std::initializer_listकाम के समान है (c ++ 11), लेकिन वे इस संदर्भ में काम नहीं करते हैं।


3

ऐसा करने का सबसे सरल तरीका है, इसे संदर्भ द्वारा वापस करना है, भले ही आप 'और' प्रतीक नहीं लिखते हों, यह स्वचालित रूप से संदर्भ में वापस आ जाता है

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

  }

2
int *fillarr(int arr[])

आप अभी भी परिणाम की तरह उपयोग कर सकते हैं

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

मुझे नहीं लगता कि 'int [] fillarr ...' कानूनी है। 'Int * fillarr' वह है जो आप सरणी-पॉइंटर तुल्यता के कारण उपयोग करेंगे।
सीलैंड

1

जैसा कि ऊपर बताया गया मार्ग सही हैं। लेकिन मुझे लगता है कि अगर हम किसी फ़ंक्शन के स्थानीय सरणी चर को कभी-कभी वापस करते हैं तो यह कचरा मानों को इसके तत्वों के रूप में वापस करता है।

इन-ऑर्डर से बचने के लिए मुझे सरणी को गतिशील रूप से बनाना और आगे बढ़ना था। जो कुछ इस तरह है।

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

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




0

0

स्रोत: https://www.tutorialspoint.com/cplusplus/cpp_return_arrays_from_functions.htm

C ++ फ़ंक्शन के तर्क के रूप में संपूर्ण सरणी को वापस करने की अनुमति नहीं देता है। हालाँकि, आप एक इंडेक्स के बिना सरणी के नाम को निर्दिष्ट करके एक सरणी में एक पॉइंटर लौटा सकते हैं।

  1. यदि आप किसी फ़ंक्शन से एकल-आयाम सरणी वापस करना चाहते हैं, तो आपको निम्न उदाहरण के रूप में एक पॉइंटर लौटाते हुए एक फ़ंक्शन घोषित करना होगा:
int * myFunction()    {
   .
   .
   .
}
  1. C ++ फ़ंक्शन के बाहर एक स्थानीय चर के पते को वापस करने की वकालत नहीं करता है, इसलिए आपको स्थानीय चर को स्थिर चर के रूप में परिभाषित करना होगा।

वर्तमान प्रश्न पर इन नियमों को लागू करते हुए, हम कार्यक्रम को इस प्रकार लिख सकते हैं:

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

आउटपुट होगा:

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


0

वास्तव में जब आप किसी फ़ंक्शन के अंदर एक सरणी पास करते हैं, तो मूल सरणी के लिए सूचक फ़ंक्शन पैरामीटर में पारित किया जाता है और इस प्रकार उस फ़ंक्शन के अंदर सरणी में किए गए परिवर्तन वास्तव में मूल सरणी पर बने होते हैं।

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

इसे चलाएं और आप परिवर्तनों को देखेंगे


1
कृपया उचित अंग्रेजी शब्दांकन (आप यूएलई के बजाय) का उपयोग करें और "दोस्त" जैसे खाली वाक्यांशों को छोड़ दें।
नरक

इसके अलावा: "तब वास्तव में इसे एक संदर्भ के रूप में पारित किया जाता है" गलत है। चर को yस्वयं की एक प्रति के रूप में पारित किया जाता है, लेकिन क्योंकि यह एक संकेतक है, आप सीधे सरणी पर काम करेंगे। कृपया अपना उत्तर संपादित करें।
नरक

stackoverflow.com/questions/5573310/… TL; DR "इस प्रकार, दो रूप समान हैं।"
नरक

हाँ यह तकनीकी रूप से एक सरणी है, आप सही कह रहे हैं, लेकिन जो कॉपी किया गया है वह सरणी के लिए एक सूचक है, न कि सरणी के लिए।
नरक

0

यहाँ इस तरह की समस्या को हल करने का एक पूरा उदाहरण है

#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

बस एक प्रकार को परिभाषित करें [] वापसी मूल्य के रूप में, जैसे:

        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)

5
यह C ++ नहीं है
एड्रियन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.