C में फ़ंक्शन में सरणी और सरणी सूचक के बीच अंतर


110

C में दो कार्यों में क्या अंतर है?

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

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

अगर मैं फ़ंक्शन को काफी लंबे अरसे में कहता हूं, तो क्या ये दोनों फ़ंक्शन अलग-अलग व्यवहार करेंगे, क्या वे स्टैक पर अधिक स्थान लेंगे?

जवाबों:


114

सबसे पहले, कुछ मानक :

(प्रोटोटाइप सहित) 6.7.5.3 समारोह declarators
...
के रूप में '' की सरणी एक पैरामीटर के 7 एक घोषणा प्रकार '' को '' करने के लिए योग्य सूचक समायोजित किया जाएगा टाइप ', जहां प्रकार क्वालिफायर (यदि हो तो) उन निर्दिष्ट कर रहे हैं भीतर [और ]सरणी प्रकार व्युत्पत्ति की। कीवर्ड हैं 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या &, इसलिए इसका प्रकार 6.2.3.1/3 के अनुसार "10-एलीमेंट 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])
{
  ...
}

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


1
कंपाइलर गलत तरीके से फ़ंक्शन नाम को दो मामलों में अलग-अलग तरीके से प्रबंधित करने के कारण (कम से कम कुछ पुराने) MSVC C ++ कंपाइलर का उपयोग करते समय एक अंतर होता है, (यह पहचानते हुए कि वे एक ही हैं अन्यथा), जिसके परिणामस्वरूप लिंक समस्याएं होती हैं। देखें यहाँ "ठीक नहीं होगा" बग रिपोर्ट connect.microsoft.com/VisualStudio/feedback/details/326874/...
greggo

29

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


1
@ कौशिक: हालाँकि वे इस मामले में एक जैसे हैं, लेकिन ध्यान रखें कि वे सामान्य मामले में
ब्लूराजा - डैनी पफ्लूघोफ्ट

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

0

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

#include <stdio.h>

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

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

जब मैं IDA में बाइनरी फ़ाइल के दोनों कॉलिंग संस्करणों के .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

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


18
क्षमा करें, लेकिन यह केवल यह साबित करता है कि gcc का कुछ संस्करण दोनों के लिए x86 पर समान असेंबली बनाता है। सही उत्तर, गलत स्पष्टीकरण।
लैम्ब्डपावर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.