2010-02-03 13 views
19

मैं हाल ही में पाया इस तरह की कुछ कोड:संदर्भ-से-सरणी पैरामीटर के बारे में क्या उपयोगी है?

typedef int TenInts[10]; 
void foo(TenInts &arr); 

क्या आप foo() के शरीर कि उपयोगी है में कर सकते हैं, कि तुम अगर घोषणा था नहीं कर सका:

void foo(int *arr); // or, 
void foo(int arr[]); // or, 
void foo(int arr[10]); // ? 

मैं एक पाया प्रश्न जो how to pass a reference to an array पूछता है। मुझे लगता है कि मैं क्यों पूछ रहा हूं

इसके अलावा, केवल one answer "केवल उपयोगी होने के लिए पॉइंटर कब होता है?" चर्चा फ़ंक्शन पैरामीटर, इसलिए मुझे नहीं लगता कि यह एक डुप्लिकेट प्रश्न है।

उत्तर

40

संदर्भ-से-सर पैरामीटर सरणी प्रकार को पॉइंटर प्रकार में क्षय करने की अनुमति नहीं देता है। यानी सटीक सरणी प्रकार फ़ंक्शन के अंदर संरक्षित रहता है। (उदाहरण के लिए, आप पैरामीटर पर sizeof arr/sizeof *arr चाल का उपयोग कर सकते हैं और तत्व गणना प्राप्त कर सकते हैं)। संकलक यह सुनिश्चित करने के लिए प्रकार की जांच भी करेगा कि सरणी तर्क प्रकार सरणी पैरामीटर प्रकार के समान है, यानी यदि पैरामीटर को 10 इन्स की सरणी के रूप में घोषित किया गया है, तो तर्क को बिल्कुल 10 की सरणी होना आवश्यक है चींटियों और कुछ भी नहीं।

वास्तव में, स्थितियों जब सरणी आकार संकलन समय पर तय हो गई है, एक संदर्भ करने वाली सरणी (या सूचक करने वाली सरणी) का उपयोग कर पैरामीटर घोषणाओं प्राथमिक के रूप में किया जा सकता है preceived में, पसंदीदा तरीका पारित करने के लिए एक सरणी। अन्य संस्करण (जब सरणी प्रकार को पॉइंटर प्रकार को क्षय करने की अनुमति दी जाती है) रन-टाइम आकार के सरणी पास करने के लिए आवश्यक है, तो परिस्थितियों के लिए आरक्षित हैं।

उदाहरण के लिए, एक समारोह के संकलन समय आकार की एक सरणी पारित करने के लिए सही तरीका

void foo(int (&arr)[10]); // reference to an array 

या

void foo(int (*arr)[10]); // pointer to an array 

एक यकीनन गलत तरीके से उपयोग करने के लिए एक "सड़ा हुआ होगा" है दृष्टिकोण

void foo(int arr[]); // pointer to an element 
// Bad practice!!! 

"क्षीण" दृष्टिकोण आम तौर पर रन-टाइम si के सरणी के लिए आरक्षित होना चाहिए Ze और सामान्य रूप से एक अलग पैरामीटर

void foo(int arr[], unsigned n); // pointer to an element 
// Passing a run-time sized array 

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

उपर्युक्त मूल रूप से अधिक सामान्य सिद्धांत का प्रत्यक्ष परिणाम है।जब आपके पास T प्रकार का "भारी" ऑब्जेक्ट होता है, तो आप इसे सामान्यतः पॉइंटर T * या संदर्भ T & द्वारा पास करते हैं। Arrays इस सामान्य सिद्धांत से कोई अपवाद नहीं है। उनके पास होने का कोई कारण नहीं है।

ध्यान रखें कि अभ्यास में अक्सर रन-टाइम आकार के सरणी के साथ काम करने वाले कार्यों को लिखना समझदारी होती है, खासकर जब जेनेरिक, लाइब्रेरी-स्तरीय कार्यों की बात आती है। ऐसे कार्य अधिक बहुमुखी हैं। इसका अर्थ यह है कि वास्तविक जीवन कोड में "क्षीण" दृष्टिकोण का उपयोग करने के लिए अक्सर एक अच्छा कारण होता है, फिर भी, यह कोड के लेखक को परिस्थितियों को पहचानने से बहाना नहीं करता है जब सरणी आकार संकलन समय पर ज्ञात होता है और संदर्भ-का उपयोग करता है तदनुसार -एरे विधि।

+0

धन्यवाद, महान जवाब। – Dan

+4

... हालांकि मैं आपके अंतिम संपादन से असहमत हूं। एक सरणी एक "भारी" वस्तु है, लेकिन आप वास्तव में मूल्य से सरणी नहीं पारित कर सकते हैं, जब तक कि आप इसे किसी संरचना या किसी चीज़ में न रखें। – Dan

7

एक अंतर यह है कि यह एक शून्य संदर्भ पारित करना असंभव है (माना जाता है)। तो सिद्धांत रूप में फ़ंक्शन को जांचने की आवश्यकता नहीं है कि पैरामीटर शून्य है, जबकि एक int * arr पैरामीटर शून्य हो सकता है।

+0

बहुत अच्छा बिंदु, कि मेरे पास नहीं हुआ था। – Dan

+0

दरअसल इस सलाह में मेयर के "अधिक प्रभाव सी ++" में समर्पित पूरा अध्याय है। * की रेखाओं में कुछ * "यदि कोई पैरामीटर शून्य हो सकता है, तो इसे पॉइंटर द्वारा पास करें, अन्यथा संदर्भ द्वारा इसे पास करें" *। – Vorac

+1

@ वोराक: हालांकि पुरानी सलाह है, हालांकि। हमें कच्चे पॉइंटर्स से बचना चाहिए, और एक पैरामीटर वैकल्पिक बनाना चाहते हैं, उनसे बचने के लिए पर्याप्त कारण नहीं है। –

0

आप यह सुनिश्चित कर सकते हैं कि फ़ंक्शन केवल int आकार 10 के सरणी पर कॉल किया गया हो। यह एक प्रकार की जांच दृष्टिकोण से उपयोगी हो सकता है।

0

आपको कार्य की अपेक्षा करने के बारे में अधिक अर्थपूर्ण अर्थ मिलता है।

2

आप संकलन समय पर किसी सरणी के आकार को जानने के लिए फ़ंक्शन टेम्पलेट लिख सकते हैं।

template<class E, size_t size> 
size_t array_size(E(&)[size]) 
{ 
    return size; 
} 

int main() 
{ 
    int test[] = {2, 3, 5, 7, 11, 13, 17, 19}; 
    std::cout << array_size(test) << std::endl; // prints 8 
} 
कोई और अधिक मेरे लिए

sizeof(test)/sizeof(test[0]) ;-)

+1

'sizeof() 'समाधान एक संकलन समय निरंतर देता है, आपका टेम्पलेट फ़ंक्शन नहीं करता है (जब तक आप C++ 0x के साथ' constexpr' जोड़ते हैं)। उदाहरण देखें यहां समाधान के लिए: http://stackoverflow.com/questions/1500363/compile-time-sizeof-array-without-using-a-macro/1500517#1500517 –

संबंधित मुद्दे