2012-03-04 30 views
39

तो मैं लगा जब समारोह संकेत कर रही है, तो आप operator & की जरूरत नहीं है प्रारंभिक समारोह का पता प्राप्त करने के पते: फिरसमारोह संकेत दिए गए और एक समारोह

>./a.out 
100.000000 
100.000000 
fun1 = 0x4004f4  &foo = 0x4004f4 
fun2 = 0x4004f4  foo = 0x4004f4 
    a = 0x7fff26804470 
&a = 0x7fff26804470 

:

#include <stdio.h> 

double foo (double x){ 
    return x*x; 
} 

int main() { 

    double (*fun1)(double) = &foo; 
    double (*fun2)(double) = foo; 

    printf("%f\n",fun1(10)); 
    printf("%f\n",fun2(10)); 

    printf("fun1 = %p \t &foo = %p\n",fun1, &foo); 
    printf("fun2 = %p \t foo = %p\n",fun2, foo);  

    int a[10]; 

    printf(" a = %p \n &a = %p \n",a,&a); 

    return 0; 
} 

उत्पादन मुझे एहसास हुआ कि यह सरणी के लिए भी सच है, जिसका अर्थ है कि यदि आपके पास int a[10] दोनों a और &a समान स्थान पर इंगित करते हैं। सरणी और कार्यों के साथ क्यों है? क्या पता किसी स्मृति स्थान में सहेजा गया है जिसमें वही पता है जैसा मूल्य (पता) में सहेजा जा रहा है?

+0

मुझे कभी समझ में नहीं आया कि आपको फ़ंक्शन का पता लेने के लिए ऑपरेटर के पते का उपयोग क्यों नहीं करना पड़ा। मैंने हमेशा यह माना है कि सिंटैक्टिक चीनी का थोड़ा सा हिस्सा है। – Bill

+0

@ बिल: बिल्कुल! यही वह है जो मैं हमेशा सोचने के लिए उपयोग करता हूं लेकिन ऐसा लगता है कि आपको इसकी आवश्यकता नहीं है! – GradGuy

+0

यदि पता उसी स्मृति स्थान में सहेजा गया था, तो वास्तविक फ़ंक्शन कोड/सरणी डेटा नहीं हो सकता है! आप व्यावहारिक रूप से एरे को पॉइंटर्स के रूप में व्यवहार करेंगे और तर्क के रूप में तर्क के रूप में कार्य किए गए कार्यों को भी करेंगे, इसलिए आपको ऑपरेटर के पते की आवश्यकता नहीं होगी। असल में, किसी फ़ंक्शन या सरणी का 'मान' बकवास है।केवल पता ही समझ में आता है, इसलिए जब आप 'मान' से पूछते हैं, और जब आप पता पूछते हैं तो आपको यह मिलता है। –

उत्तर

58

int a[10] दिया गया, a और &a दोनों एक ही पते उत्पन्न करते हैं, हाँ, लेकिन उनके प्रकार अलग हैं।

aint[10] प्रकार का है। जब इसे निहित रूप से एक सूचक प्रकार में परिवर्तित किया जाता है, तो सूचक int* प्रकार का होता है और सरणी के प्रारंभिक तत्व को इंगित करता है। &a टाइप int (*)[10] (यानी, दस पूर्णांक की सरणी के लिए एक सूचक) है। चूंकि किसी सरणी में कोई पैडिंग नहीं हो सकती है, इसलिए वे दोनों मूल्य के साथ पॉइंटर्स उत्पन्न करते हैं, लेकिन पॉइंटर्स के पास प्रकार अलग-अलग होते हैं।

फ़ंक्शंस सरणी के समान हैं, लेकिन पूरी तरह से समान नहीं हैं। आपका फ़ंक्शन foodouble(double) प्रकार का है। जब भी foo अभिव्यक्ति में उपयोग किया जाता है और यह असी & ऑपरेटर का संचालन नहीं है, तो यह निश्चित रूप से एक सूचक में परिवर्तित हो जाता है, जो double(*)(double) प्रकार का है।

तो, सभी व्यावहारिक उद्देश्यों के लिए, एक समारोह का नाम और एक ही फ़ंक्शन के लिए एक सूचक, एक दूसरे के लिए विचलित है। कुछ subtleties हैं, जिनमें से सभी मैं "Why do all these crazy function pointer definitions all work? What is really going on?" के जवाब में चर्चा करता हूं (उस प्रश्न को सी ++ के बारे में पूछा गया था, लेकिन सी ++ में गैर-सदस्य कार्यों के लिए नियम सी में कार्यों के समान हैं।

8

नहीं, कोई अतिरिक्त नहीं है कार्य/सरणी को इंगित करने के लिए समर्पित भंडारण।

अधिकांश चर के साथ variable_name उस चर के पते को प्राप्त करने के अलावा अन्य अर्थ है, इसलिए आपको पता पाने के लिए &variable का उपयोग करने की आवश्यकता है।

फ़ंक्शन या सरणी के साथ, function_name (स्वयं द्वारा, ब्रांड्स के बाद नहीं) का कोई अन्य अर्थ नहीं है, इसलिए फ़ंक्शन का पता लेने के रूप में इसे समझने में कोई समस्या नहीं थी।

रिवर्स में

इसी तरह: एक सामान्य सूचक स्पष्ट dereferenced किए जाने की आवश्यकता है, लेकिन एक समारोह के लिए एक सूचक (फिर कोई अन्य उचित व्याख्या है, क्योंकि,) नहीं है, इसलिए की तरह एक समारोह के लिए एक सूचक दिया:

int (*func)(param_list); 

निम्नलिखित एक दूसरे के बराबर हैं - जो कुछ भी समारोह func बिंदुओं पर दोनों कॉल:

(*func)(params); 

func(params); 
+2

हालांकि थोड़ा सा होना प्रतीत होता है, क्योंकि [10], (* ए) [5] वैध कॉल नहीं है – GradGuy

1

मूल रूप से, के बाद से समारोह नाम एक समारोह होने के लिए जाना जाता है "" है, & सख्ती से nec नहीं है essary। यह व्यवहार सरणी के लिए समान है। याद रखें कि एक फ़ंक्शन स्वयं एक चर नहीं है, इसलिए यह कभी-कभी अपेक्षाकृत अपेक्षाकृत थोड़ा अलग व्यवहार करता है।आप कश्मीर & आर के 2 संस्करण है, तो आप काम करता है, या अंत में संदर्भ मैनुअल की ओर इशारा पर खंड 5.11 की जाँच कर सकते हैं,

धारा A7.1 सूचक पीढ़ी: अगर एक अभिव्यक्ति के प्रकार या उप-संपीड़न कुछ प्रकार टी के लिए "टी की सरणी" है, तो अभिव्यक्ति का मान सरणी में पहली वस्तु के लिए एक सूचक है, और अभिव्यक्ति के प्रकार को "पॉइंटर टू टी" में बदल दिया गया है। इस रूपांतरण अभिव्यक्ति की जगह एकल & ऑपरेटर, के संकार्य है प्रकार की अभिव्यक्ति नहीं ले करता है ... इसी प्रकार, "समारोह लौटने टी," जब & ऑपरेटर के संकार्य के रूप में इस्तेमाल के अलावा, में बदल जाती है "टी वापस लौटने के लिए सूचक टी।"

धारा A7.4.2 पता ऑपरेटर: एकल & ऑपरेटर अपनी संकार्य का पता लेता है .... परिणाम वस्तु या समारोह lvalue से संबोधित किया जाता करने के लिए एक सूचक है। यदि ऑपरेंड का प्रकार टी है, तो परिणाम के प्रकार "टी के लिए सूचक" है।

जहां तक ​​मुझे पता है, यह सी 99 के लिए समान है।

0

printf ("fun1 =% p \ t & foo =% p \ n", fun1, foo);

यहाँ अपने साथ pass by value और

printf समारोह सूचक पारित करके foo बुला रहे हैं

("fun2 =% p \ t foo =% p \ n", fun2, & foo)

यहाँ आप pass by reference

बो के साथ समारोह सूचक पारित करके &foo बुला रहे हैं वें मामले में आप केवल printf को फ़ंक्शन पॉइंटर के साथ कॉल कर रहे हैं।

याद रखें foo स्वयं function pointer value और एक चर नहीं है।

सरणी के साथ ही होता है। int arr[10] 10 इंटीग्रियों के निरंतर ब्लॉक प्राप्त करने में अनुवाद करता है और पहले तत्व के पते को एआर में संग्रहीत किया जाता है। तो एआर भी एक सूचक है।

0

fun और &fun बिल्कुल वही हैं (सिवाय इसके कि आकार (एफ) अवैध है)। a और &a पॉइंटर अंकगणित के समान हैं: a + 10 == &a + 1, क्योंकि 10*sizeof(*a) == sizeof(a) (जहां sizeof(*a) == sizeof(int))।

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