2012-07-23 16 views
10

मैं एक सरणी की लंबाई प्राप्त करना चाहता हूं, int array[] = {1, 2, 3, 4} कहें। मैंने ऐसा करने के लिए sizeof का उपयोग किया।क्यों आकार (param_array) सूचक का आकार है?

int length(int array[]) 
{ 
    return sizeof(array)/sizeof(int); 
} 

int main() 
{ 
    int array[] = {1, 2, 3, 4}; 
    printf("%d\n", length(array)); // print 1 
    printf("%d\n", sizeof(array)/sizeof(int)); // print 4 
} 

तो, क्यों समारोह lengtharray का सूचक आकार रिटर्न में sizeof(array)? लेकिन समारोह में main, यह काम करता है।

और, मुझे सरणी की लंबाई प्राप्त करने के लिए length फ़ंक्शन को कैसे संशोधित करना चाहिए?

+1

हाँ, मैं जानता हूँ कि यह एक सी ++ सवाल है, लेकिन यह सी के रूप में अच्छी के विषय में बहुत ही उपयोगी जानकारी होती है: http://stackoverflow.com/questions/4810664/how-do-i-use-arrays-in -सी – chris

उत्तर

18

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

int length(int array[]);

int length(int *array);

तो के बराबर है।

(C99, 6.7.5.3p7) प्रकार की सरणी "के रूप में एक पैरामीटर का एक घोषणा" टाइप करने के लिए "योग्य सूचक है, जहां प्रकार क्वालिफायर (यदि हो तो) उन के भीतर निर्दिष्ट कर रहे हैं" करने के लिए समायोजित किया जाएगा " सरणी प्रकार व्युत्पन्न के [और]। "

+4

... और इसका निहितार्थ यह है कि आप काम करने के लिए 'लंबाई()' को फिर से लिख नहीं सकते हैं - यदि किसी फ़ंक्शन को किसी सरणी के आकार को जानने की आवश्यकता है, तो उसे उस फ़ंक्शन को एक अलग पैरामीटर के रूप में पारित करने की आवश्यकता है। – caf

+0

@caf मैं आपसे सहमत हूं। अतिरिक्त जानकारी के लिए, यह इस तरह से करना समझ में आता है, खासकर जब आर 0, आर 1, आर 2, आर 3 32-बिट रजिस्ट्रार के साथ एआरएम प्रोसेसर पर। इसलिए स्टैक का उपयोग करने के बजाए एक पॉइंटर आर 0 में पारित किया जा सकता है। –

2

सी चर के साथ सरणी के आकार के बारे में रनटाइम मेटाडेटा स्टोर नहीं करता है। आपको खुद को कहीं भी स्टोर करना होगा।

अपने विधि लंबाई के संदर्भ में के प्रकार पूर्णांक [] एक चर स्मृति का एक ब्लॉक करने के लिए सिर्फ एक सूचक है। यही कारण है कि आकार आपके सिस्टम पर किसी भी अन्य सूचक के आकार के समान है।

यह बजाय सरणी के कब्जे में बाइट की संख्या वापस आ जाएगी sizeof (अपने मुख्य समारोह के रूप में) संकलन समय पर सरणी की पहुंच है जब।

+1

"प्रकार का एक चर int [] स्मृति के ब्लॉक के लिए सिर्फ एक सूचक है" - यह सामान्य स्थिति में गलत है। प्रकार का int 'int [] '* * स्मृति का एक ब्लॉक है। यह एक सूचक नहीं है। एकमात्र संदर्भ जहां 'int []' सूचक के लिए खड़ा है, पैरामीटर घोषणा है और यह एक * विशेष मामला * है। – AnT

+0

स्पष्ट है कि यह विधि लंबाई() * के संदर्भ में एक सूचक * है। यह बात बताने के लिए धन्यवाद। –

3

मुख्य कार्यक्रम में, कंपाइलर सरणी की लंबाई जानता है। Subroutine में, यह नहीं करता है। विशेष रूप से, एक subroutine में, प्रकार int[] का पैरामीटर int * प्रकार के पैरामीटर के समान है। मुख्य कार्यक्रम में, दूसरी ओर, array में int[4] टाइप किया गया है। (आप array पर array पर दूसरे मान को असाइन करने का प्रयास कर परीक्षण कर सकते हैं। संकलक शिकायत करेगा।)

0

क्योंकि लम्बाई के अंदर परिवर्तनीय सरणी बाहर की तरह नहीं है। आपको मुख्य फ़ंक्शन में आकार (सरणी)/sizeof (int) रखना होगा।

4

जब आप इसे किसी फ़ंक्शन में पास करते हैं तो सरणी एक पॉइंटर में क्षीण हो जाती है। ताकि length सरणी की दूरी प्राप्त कर सकते हैं

0

अपने कोड को संशोधित, यह एक मैक्रो में बदल जाते हैं करने के लिए:

#define length(x) (sizeof(x)/sizeof(*x)) 

अपने कोड नमूने के लिए, जैसा कि आप उम्मीद करते हैं इस व्यवहार करेगा।

ध्यान दें कि यह स्थिर-आवंटित सरणियों पर केवल काम करते हैं, और केवल जब मूल सरणी का उपयोग कर कहा जाता है (यह जब सरणी के लिए एक सूचक का उपयोग कर काम नहीं करेगा) होगा। ऐसा इसलिए है क्योंकि जब आप sizeof(x) लिखते हैं, जहां x एक सरणी के लिए एक सूचक है, तो संकलक इसे शाब्दिक रूप से व्याख्या करता है। x मैपिंग के किसी भी तरीके से उस सरणी पर वापस नहीं है जो sizeof का मूल्यांकन करने से पहले इंगित करता है।

1

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

int length(int n, int (* array)[n]) 
{ 
    return sizeof(*array)/sizeof(int); 
} 

int main() 
{ 
    int array[] = {1, 2, 3, 4}; 
    printf("%d\n", length(4, &array)); // print 1 
    printf("%d\n", sizeof(array)/sizeof(int)); // print 4 
} 

मैं नहीं जानता कि क्या अच्छा है कि वास्तव में के बाद से आकार पहले से ही प्रदान की जाती है, तो आप करता है, हालांकि पहले स्थान पर। लेकिन आप देखते हैं कि sizeof ऑपरेटर काम करता है जैसा कि आप इस मामले में चाहते थे।

4

जैसा कि अन्य उत्तरदाताओं ने ध्यान दिया है, एक सरणी लेने के लिए घोषित एक फ़ंक्शन को संकलित किया गया है जैसे कि यह एक सूचक लेता है।

आपकी लंबाई विधि करने के लिए मैंने देखा है कि सबसे आम तरीका #define के साथ है, लेकिन यदि आप टेम्पलेट्स के साथ चाल खेलते हैं, तो आप अपना कार्य कार्य कर सकते हैं।

template <size_t _Size> inline int length(int(& array)[_Size]) 
{ 
    //return sizeof(array)/sizeof(int); 
    return _Size; 
}; 

int array[] = {1, 2, 3, 4}; 
printf("%d\n", length(array)); // print 4 
लंबाई 4 के अपने सरणी के साथ

, यह एक विधि है कि लंबाई 4 की एक सरणी लेता है के रूप में संकलित हो जाता है, और रिटर्न एक स्थिर 4. यह भी फायदा है कि कि नहीं है अगर आप कुछ पारित करने के लिए कोशिश एक सरणी, संकलक एक त्रुटि देगा, जबकि # परिभाषा विधि नहीं है।

int* foo = array; 
printf("%d\n", length(foo)); 
    // error C2784: 'int length(int (&)[_Size])' : could not deduce template 
    //  argument for 'int (&)[_Size]' from 'int *' 
    // test.cpp(56) : see declaration of 'length' 
+1

प्रश्न टैग सी, सी ++ नहीं। – jxh

+0

आह, बिल्कुल सही। ओह ठीक है, शायद वह इसे वैसे भी उपयोगी लगेगा। –

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