सी

2011-04-06 22 views
88

में फ़ंक्शन में गुजरने वाले सरणी और सरणी सूचक के बीच अंतर सी में दो कार्यों के बीच क्या अंतर है?सी

void f1(double a[]) { 
    //... 
} 

void f2(double *a) { 
    //... 
} 

अगर मैं थे एक काफी लंबे समय सारणी पर कार्यों कॉल करने के लिए, इन दोनों कार्यों अलग ढंग से व्यवहार होता था, ये ढेर पर अधिक स्थान ले जाएगा?

उत्तर

96

सबसे पहले, कुछ standardese:

6.7.5.3 समारोह declarators (प्रोटोटाइप सहित)
...
7 के रूप में '' प्रकार की सरणी 'एक पैरामीटर का एक घोषणा' होगा टाइप '' टाइप किए गए क्वालीफायर (यदि कोई हैं) सरणी प्रकार डेरिवा के योग्य क्वालिफ़ायर (यदि कोई हैं) में निर्दिष्ट पॉइंटर को समायोजित किया गया है tion। यदि static [ और ] सरणी प्रकार व्युत्पन्न के भीतर भी दिखाई देता है, तो फ़ंक्शन पर प्रत्येक कॉल के लिए, संबंधित वास्तविक तर्क का मान कम से कम के साथ सरणी के पहले तत्व तक पहुंच प्रदान करेगा आकार अभिव्यक्ति द्वारा निर्दिष्ट तत्वों।

तो, संक्षेप में, किसी भी समारोह पैरामीटर T a[] या T a[N] के रूप में घोषित इलाज किया है जैसे कि यह T *a घोषित किया गया है।

तो, सरणी पैरामीटर क्यों मानते हैं कि उन्हें पॉइंटर्स के रूप में घोषित किया गया था? यहां कारण बताया:

6.3.2.1 Lvalues, सरणियों, और समारोह designators
...
3 जब यह sizeof ऑपरेटर या एकल & ऑपरेटर के संकार्य है, या एक स्ट्रिंग शाब्दिक है सिवाय एक सरणी, एक अभिव्यक्ति 'टाइप' है 'कि की प्रारंभिक तत्व को सरणी वस्तु बताते हैं और' प्रकार सूचक 'टाइप के साथ' एक अभिव्यक्ति के लिए परिवर्तित कर ' प्रकार की सरणी' है कि प्रारंभ करने में इस्तेमाल किया एक लालसा नहीं। यदि सरणी ऑब्जेक्ट में स्टोरेज क्लास पंजीकृत है, तो व्यवहार अपरिभाषित है।

निम्नलिखित कोड को देखते हुए:

int main(void) 
{ 
    int arr[10]; 
    foo(arr); 
    ... 
} 

कॉल में foo करने के लिए, सरणी अभिव्यक्ति arr नहीं या तो sizeof या & के संकार्य, तो अपने प्रकार परोक्ष "10 तत्व सरणी से बदल जाती है है 6.212.1/3 के अनुसार int "से" पॉइंटर int "। इस प्रकार, foo को सरणी मान के बजाय पॉइंटर मान प्राप्त होगा।

6.7.5.3/7 के कारण, आप foo रूप

void foo(int a[]) // or int a[10] 
{ 
    ... 
} 

लिख सकते हैं, लेकिन जैसा कि

void foo(int *a) 
{ 
    ... 
} 

इस प्रकार, दो रूपों समान हैं यह समझ लिया जाएगा।

6.7.5.3/7 में अंतिम वाक्य C99 के साथ पेश किया गया था, और मूल रूप से मतलब है कि अगर आप की तरह

void foo(int a[static 10]) 
{ 
    ... 
} 

एक पैरामीटर घोषणा की है वास्तविक पैरामीटर a करने के लिए इसी कम से कम साथ श्रेणी होनी चाहिए 10 तत्व।

+1

कंप्रेसर के कारण दो मामलों में गलत तरीके से फ़ंक्शन नाम को गलत तरीके से उलझाने के कारण (कम से कम कुछ पुराने) एमएसवीसी सी ++ कंपाइलर्स का उपयोग करते समय एक अंतर होता है (जबकि यह पहचानते हुए कि वे अन्यथा समान हैं), जिसके परिणामस्वरूप लिंक समस्याएं होती हैं। यहां बग रिपोर्ट "ठीक नहीं होगी" देखें http://connect.microsoft.com/VisualStudio/feedback/details/326874/inconsistent-name-mangling-for-functions-accepting-array-and- सूचक-parameters – greggo

27

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

+1

@ कौशिक: हालांकि वे इस मामले में समान हैं, लेकिन ध्यान रखें कि वे समान नहीं हैं [सामान्य मामले में] (http://stackoverflow.com/questions/2096448/do-these-statements-about -पॉइंटर्स-द-द-ए-इफेक्ट) –

+0

@ ब्लूराजा: हाँ, यह सी के नुकसान में से एक है। फ़ंक्शन पैरामीटर की घोषणा स्थानीय चर की घोषणा के लिए हर समान_ है, लेकिन कुछ सूक्ष्म मतभेद हैं (जैसे इस सरणी-से-पॉइंटर स्वचालित ट्रांसफॉर्म के रूप में) जो अनचाहे प्रोग्रामर काटने के लिए प्रवण हैं। –

-2

नहीं, उनके बीच कोई अंतर नहीं है। मैं देव सी में इस सी कोड लिखा परीक्षण करने के लिए ++ (MinGW) संकलक:

#include <stdio.h> 

void function(int* array) { 
    int a =5; 
} 

void main() { 
    int array[]={2,4}; 
    function(array); 
    getch(); 
} 

जब मैं आईडीए में बाइनरी फ़ाइल के दोनों बुला संस्करणों में से .exe में एकत्रित न मुख्य समारोह मैं बिल्कुल नीचे की तरह एक ही विधानसभा कोड प्राप्त :

push ebp 
mov  ebp, esp 
sub  esp, 18h 
and  esp, 0FFFFFFF0h 
mov  eax, 0 
add  eax, 0Fh 
add  eax, 0Fh 
shr  eax, 4 
shl  eax, 4 
mov  [ebp+var_C], eax 
mov  eax, [ebp+var_C] 
call sub_401730 
call sub_4013D0 
mov  [ebp+var_8], 2 
mov  [ebp+var_4], 4 
lea  eax, [ebp+var_8] 
mov  [esp+18h+var_18], eax 
call sub_401290 
call _getch 
leave 
retn 

तो इस कॉल के दो संस्करणों के बीच कोई अंतर नहीं है, कम से कम संकलक उन्हें समान रूप से धमकाता है।

+15

क्षमा करें, लेकिन यह केवल साबित करता है कि जीसीसी का कुछ संस्करण दोनों के लिए x86 पर एक ही असेंबली उत्पन्न करता है। सही जवाब, गलत स्पष्टीकरण। – lambdapower