2016-03-10 4 views
5

मुझे पता है कि जब मैं एक समारोह के लिए एक सरणी पास करना चाहते हैं, यह सूचक में है, तो इसके आकार नहीं जाना क्षय होगा और इन दो घोषणाओं के बराबर हैं:सी ++ में संकलक के संदर्भ में संदर्भ द्वारा किसी फ़ंक्शन को पास किए गए सरणी का आकार क्यों है?

void funtion(int *tab, int size); 

और

void funtion(int tab[], int size); 

और मैं समझता हूं क्यों। हालांकि, मैं जाँच की है कि जब मैं एक संदर्भ के रूप में एक सरणी पारित:

void funtion(int (&tab)[4]); 

संकलक सरणी के आकार को पता चल जाएगा और मुझे इस समारोह के एक तर्क के रूप में विभिन्न आकार की एक सरणी पारित नहीं होंगे।

वह क्यों है? मुझे पता है कि जब मैं पते से एक सरणी पास करता हूं, तो ith तत्व की स्थिति की गणना करते समय आकार को ध्यान में नहीं रखा जाता है, इसलिए इसे स्पष्ट रूप से फ़ंक्शन घोषणा में शामिल करने के बावजूद इसे छोड़ दिया जाता है:

void funtion(int tab[4], int size); 

लेकिन जब मैं संदर्भ द्वारा सरणी पास करता हूं तो अलग क्या होता है? इसका आकार कंपाइलर के लिए क्यों जाना जाता है?

नोट: मुझे उन सरणी में दिलचस्पी है जिनके आकार संकलन समय पर ज्ञात हैं, इसलिए मैंने किसी भी टेम्पलेट का उपयोग नहीं किया।

मैं स्टैक ओवरफ़्लो पर a similar question पाया, लेकिन यह मेरे सवाल का जवाब नहीं है - यह की व्याख्या नहीं करता क्यों संकलक सरणी के आकार को जानता है, कितना कार्यों के लिए सरणियों पारित करने के लिए पर कुछ जानकारी नहीं है।

उत्तर

6

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

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

एक चेक जोड़ा जा सकता है? संभवतः, लेकिन यह सीमित उपयोग का होगा (चूंकि हम सभी अब std :: array का उपयोग कर रहे हैं - दाएं !?), और क्योंकि यह निस्संदेह कुछ कोड तोड़ देगा। यह, उदाहरण के लिए:

void func (char Values [4]); 
func ("x"); 

यह वर्तमान में कानूनी है, लेकिन सरणी आकार पर अतिरिक्त जांच के साथ नहीं होगा।

+0

धन्यवाद :) यह शायद एक बेवकूफ सवाल है, लेकिन एक संकेतक संदर्भ संदर्भ में एक संकेतक द्वारा पारित क्यों नहीं किया जाता है? और क्यों एक चेक ब्रेक जोड़ना कुछ कोड मानते हुए यह अब अच्छा काम करता है? – user2738748

+3

@ user2738748 सूचक को खस्ताहाल सी का एक भयानक विरासत कोई भी यह पसंद करती है, लेकिन यह यह, सी ++ में इसे बदलने के लिए मुश्किल है के बाद से वहाँ एक निश्चित सी ++ संभव के रूप में संकलक के साथ के रूप में ज्यादा सी कोड compilable करने की इच्छा है। लेकिन चूंकि सी में कोई संदर्भ नहीं है, सी ++ उनके बारे में कोई नियम निर्धारित कर सकता है, अनबाउंड। और सेन नियम निर्धारित किए गए थे। – SergeyA

0

क्योंकि वहाँ कोई अजीब निहित प्रकार परिवर्तन मामले में संकलक द्वारा की गई है।आम तौर पर जब आप लिखते हैं:

void func(int[4]); 

या

void func(void()); 

संकलक आप "मदद" करने का फैसला करता है और में उन अनुवाद:

void func(int *); 

या

void func(void(*)()); 

अजीब बात है हालांकि बात - मैं टी आपको इस तरह से सहायता नहीं करेगा जब आप उनमें से किसी एक को वापस करने का प्रयास करें। लिखने की कोशिश करें:

int func()[4], func1()(); 

ओह - आश्चर्य - संकलक त्रुटि।

अन्यथा सरणी सरणी हैं और निरंतर आकार है जिसे sizeof ऑपरेटर का उपयोग करके अधिग्रहित किया जा सकता है।

हालांकि यह उपरोक्त वर्णित कंपाइलर व्यवहार के कारण अक्सर भूल जाता है और जब भी अपेक्षित नहीं होता है तो सरणी प्रकार की वस्तुओं पर लागू निहित सूचक रूपांतरण की वजह से भूल जाता है। और यह अक्सर होता है।

size_t arr[4], 

    (*parr)[3] = &arr, //taking the address of array 

    (&refarr)[3] = arr, //storing reference to array 

    sizearrobject = sizeof(arr); //taking the array object size 

उपरोक्त उदाहरण क्योंकि दूसरे और तीसरे लाइन पर असंगत प्रकार के संकलक त्रुटि ट्रिगर करेंगे: यहाँ हालांकि कुछ अपवादों को छोड़कर, जब कोई अंतर्निहित सरणी वस्तु रूपांतरण लागू किया जाता है कर रहे हैं।

मैं मामलों के बारे में बात कर रहा हूँ जब arr वस्तु स्वचालित रूप से कुछ इस तरह करने के लिए परिवर्तित नहीं कर रहा है:

(size_t*)&arr 
0

ठीक है, कार्य करने के लिए एक सरणी पारित करने के लिए कई तरीके हैं। आप पॉइंटर द्वारा संदर्भ द्वारा इसे पास कर सकते हैं, और दोनों तरीकों से स्पष्ट रूप से परिभाषित करने के तरीके को परिभाषित करने के तरीके हैं। तुम क्यों केवल में आकार निर्दिष्ट करना होगा void f(int (&arr)[size])

आप से पूछना:

  • सूचक पहला तत्व के लिए: एक पूरी सरणी void f(int *arr)
  • संदर्भ
    अपने प्रश्न में आप इन 2 तरीके की तुलना इन मामलों में से एक।

    ऐसा लगता है कि आप मानते हैं कि उनके बीच एकमात्र अंतर यह तथ्य है कि कोई सूचक और अन्य उपयोग संदर्भ का उपयोग करता है। लेकिन यह कथन गलत है, उनके पास और अंतर हैं: एक पॉइंटर पहला तत्व है, लेकिन दूसरा का एक संपूर्ण सरणी का संदर्भ है।


    आप एक पूरे सरणी सूचक द्वारा एक सरणी पारित कर सकते हैं:

    void f(int (*arr)[size]) 
    

    अपने उदाहरण के साथ यह तुलना एक पूरी सरणी refence द्वारा पारित होने के साथ,:

    void f(int (&arr)[size])  
    

    वे समान हैं, वे है समान वाक्यविन्यास, वे स्पष्ट रूप से सरणी आकार को परिभाषित करते हैं।


    इसके अलावा, इस पर विचार करें:

    void f(int &arr) 
    

    यह संदर्भ द्वारा एक भी पूर्णांक गुजर तरह लग रहा है, लेकिन आप इसे करने के लिए अज्ञात आकार की एक सरणी पारित कर सकते हैं। यह करने के लिए

    सूचक विकल्प

    void f(int *arr) 
    

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

    जैसा कि मैंने कहा, आप सूचक या संदर्भ का उपयोग कर सकते हैं। और आप सरणी आकार निर्दिष्ट कर सकते हैं या आप किसी भी आकार की सरणी का उपयोग करने की अनुमति दे सकते हैं। ये दोनों जुड़े नहीं हैं।

    //      by pointer    by reference 
    /* Any size */ void f(int *arr)  void f(int &arr) 
    /* Specific size */ void f(int (*arr)[x]) void f(int (&arr)[x]) 
    
संबंधित मुद्दे