2010-01-09 9 views
6

जब मैं एक समारोह के लिए एक सरणी पास करनी होगी, ऐसा लगता है समारोह निम्न में से सभी घोषणाओंसरणी प्रकार - समारोह पैरामीटर के रूप में काम/उपयोग के लिए नियम

void f(int arr[]) 
void f(int arr[4]) // is this one correct? 
इस के लिए

काम करेगा:

int a[]={1,2,3,4}; 
f(a); 

लेकिन जब मैं एक और सरणी के लिए एक सरणी में असाइन करें, यह विफल

int a[]={1,2,3,4}; 
int b[4] = a; // error: array must be initialized with a brace-enclosed initializer 

तो क्यों एक सरणी एक argum के रूप में पारित एक समारोह की ent ठीक है, लेकिन सरल असाइनमेंट के rhs पर इस्तेमाल गलत है?

+3

प्रश्न के शीर्षक को फिर से लिखना होगा, वर्तमान में अत्यधिक सामान्य और लोअरकेस है। –

उत्तर

12

इस्तेमाल किया गया है, हम दो अलग अलग संदर्भों समझने की जरूरत है।

  • मूल्य संदर्भों में, प्रकार T की एक सरणी के नाम एक सूचक टाइप करने के लिए करने के लिए T बराबर है, और सरणी के पहले तत्व के लिए सूचक के बराबर है।
  • ऑब्जेक्ट संदर्भों में, T प्रकार की एक सरणी का नाम एक सूचक को कम नहीं करता है।

ऑब्जेक्ट संदर्भ क्या है?

a = b;, a ऑब्जेक्ट संदर्भ में है। जब आप एक चर का पता लेते हैं, तो इसका उपयोग ऑब्जेक्ट संदर्भ में किया जाता है। अंत में, जब आप एक चर पर sizeof ऑपरेटर का उपयोग करते हैं, तो इसका उपयोग ऑब्जेक्ट संदर्भ में किया जाता है। अन्य सभी मामलों में, वैरिएबल संदर्भ में एक चर का उपयोग किया जाता है।

अब हम इस ज्ञान है कि, जब हम करते हैं:

void f(int arr[4]); 

यह है बिल्कुल बराबर करने के लिए

void f(int *arr); 

आप को पता चला रूप में, हम (ऊपर 4) आकार छोड़ सकते हैं समारोह घोषणा से। इसका मतलब है कि आप f() पर "सरणी" के आकार को नहीं जान सकते हैं।बाद में, जब आप ऐसा करेंगे:

int a[]={1,2,3,4}; 
f(a); 

समारोह कॉल में, नाम a मूल्य के संदर्भ में है, इसलिए यह int के लिए सूचक को कम करता है। यह अच्छा है, क्योंकि f एक सूचक को int पर अपेक्षा करता है, इसलिए फ़ंक्शन परिभाषा और उपयोग मिलान। f() को पास किया गया है a (&a[0]) के पहले तत्व का सूचक है।

int a[]={1,2,3,4}; 
int b[4] = a; 

नाम b के मामले में एक वस्तु के संदर्भ में प्रयोग किया जाता है, और एक सूचक को कम नहीं करता। (संयोग से, a यहाँ एक मूल्य के संदर्भ में है, और एक सूचक को कम करता है।)

अब, रों के भंडारण के लायक प्रदान करती है और इसे करने के लिए नाम b देता है। a को भी इसी तरह का भंडारण सौंपा गया था। तो, असल में, उपर्युक्त असाइनमेंट का अर्थ है, "मैं भंडारण स्थान को पिछले स्थान जैसा ही बनाना चाहता हूं"। यह समझ में नहीं आता है।

आप प्रतिलिपिb में a की सामग्री चाहते हैं, तो आप कर सकता है:

#include <string.h> 
int b[4]; 
memcpy(b, a, sizeof b); 

या, यदि आप एक सूचक b कि a की ओर इशारा करना चाहता था:

int *b = a; 

यहां, a मूल्य संदर्भ में है, और int पर एक सूचक को कम कर देता है, इसलिए हम a को असाइन कर सकते हैं एक int *

अंत में, जब एक सरणी आरंभ, आप इसे स्पष्ट मान को असाइन कर सकते हैं:

int a[] = {1, 2, 3, 4}; 

यहाँ, एक 4 तत्वों, प्रारंभ हो जाता है 1, 2, 3, और 4 के लिए आप भी कर सकता है :

int a[4] = {1, 2, 3, 4}; 

यदि सरणी में तत्वों की संख्या की तुलना में सूची में कम तत्व हैं, तो शेष मान 0 होने के लिए लिया जाता है:

int a[4] = {1, 2}; 

सेट a[2] और 0.

+0

बहुत अच्छी तरह से लिखा गया है। – benzado

+0

क्या आप ऑब्जेक्ट और मूल्य संदर्भों के बारे में पढ़ते हैं, इस पर एक संदर्भ प्रदान कर सकते हैं? मैं हूं –

+0

मैंने कभी "ऑब्जेक्ट संदर्भ" बनाम "मूल्य संदर्भ" के बारे में नहीं सुना है। –

7
void f(int arr[]); 
void f(int arr[4]); 

वाक्यविन्यास भ्रामक है। वे दोनों इस तरह के हैं:

void f(int *arr); 

यानी, आप सरणी की शुरुआत में एक सूचक पास कर रहे हैं। आप सरणी की प्रतिलिपि नहीं बना रहे हैं।

+3

हां, हालांकि (सी 99 में) 'शून्य एफ (int arr [static 4]) {...}' विशेष है क्योंकि यह संकलक को यह मानने की अनुमति देता है कि 'arr' non-'NULL' है और कम से कम आकार है 4. – Jed

6

सी सरणी के असाइनमेंट का समर्थन नहीं करता है। फ़ंक्शन कॉल के मामले में, सरणी एक सूचक को तय करती है। सी पॉइंटर्स के असाइनमेंट का समर्थन करता है। यह यहां हर दिन पूछा जाता है - क्या सी पाठ पुस्तक आप लोग पढ़ रहे हैं जो इसे समझाती नहीं है?

3

memcpy आज़माएं।

int a[]={1,2,3,4}; 
int b[4]; 
memcpy(b, a, sizeof(b)); 

उनका कहना है कि बाहर के लिए धन्यवाद, स्टीव, यह कुछ समय के बाद से मैं अंतर को समझने के लिए सी

+1

'memcpy (बी, ए, 4 * आकार (int)' या 'sizeof (बी)' –

1

को a[3] इसके बारे में अपने अंतर्ज्ञान पाने के लिए आपको समझना चाहिए क्या मशीन स्तर पर चल रहा है।

प्रारंभिक अर्थशास्त्र (= {1,2,3,4}) का अर्थ है "इसे अपनी बाइनरी छवि पर बिल्कुल इस तरह रखें" ताकि इसे संकलित किया जा सके।

ऐरे असाइनमेंट अलग होगा: कंपाइलर को इसे एक लूप में अनुवाद करना होगा, जो वास्तव में तत्वों पर होगा। सी कंपाइलर (या सी ++, उस मामले के लिए) ऐसी चीज कभी नहीं करता है। यह सही ढंग से आपको यह करने की उम्मीद करता है। क्यूं कर? क्योंकि, तुम कर सकते हो। तो, यह एक subroutine होना चाहिए, सी (memcpy) में लिखा है।यह सब आपके हथियार के सादगी और निकटता के बारे में है, जो सी और सी ++ के बारे में है।

0

ध्यान दें कि aint a[4] में int [4] है।

लेकिन typeof (&a) == int (*)[4]! = int [4]

भी ध्यान रखें कि मूल्य के प्रकार a कीint * है, जो ऊपर के सभी से अलग है!

int main() { 
    // All of these are different, incompatible types!  
    printf("%d\n", sizeof (int[4])); // 16 
    // These two may be the same size, but are *not* interchangeable! 
    printf("%d\n", sizeof (int (*)[4])); // 4 
    printf("%d\n", sizeof (int *)); // 4 
} 
+0

आपको size_t (C99 में) मुद्रित करने के लिए "% zu" का उपयोग करना चाहिए। – Jens

0

मैं स्पष्ट करना चाहते हैं:

यहां एक नमूना कार्यक्रम तुम कोशिश कर सकते है।

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

लेकिन औपचारिक तर्क ही नहीं हैं: जवाब में कुछ भ्रामक संकेत कर रहे हैं ... सभी निम्नलिखित कार्य पूर्णांक सरणियों ले सकते हैं। तो संकलक उन्हें अलग-अलग संभाल सकता है। आंतरिक स्मृति प्रबंधन के अर्थ में, सभी तर्क पॉइंटर्स की ओर ले जाते हैं।

void f(int arr[]) 

... f() किसी भी आकार की सरणी लेता है।

void f(int arr[4]) 

... औपचारिक तर्क एक सरणी आकार इंगित करता है।

void f(int *arr) 

... आप एक पूर्णांक सूचक भी पास कर सकते हैं। एफ() आकार के बारे में कुछ भी नहीं जानता है।

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