आप C में पैरामीटर के रूप में फ़ंक्शन कैसे पास करते हैं?


615

मैं एक फ़ंक्शन बनाना चाहता हूं जो डेटा के सेट पर पैरामीटर द्वारा पारित एक फ़ंक्शन करता है। आप C में पैरामीटर के रूप में फ़ंक्शन कैसे पास करते हैं?


12
यदि आप फ़ंक्शन / सरणियों को चर के रूप में उपयोग कर रहे हैं, तो हमेशा उपयोग करें typedef
मूइंग डक


फ़ंक्शन का नाम फ़ंक्शन के लिए एक पॉंटर होना चाहिए। C सीखने वाले ज्यादातर लोग जल्दी या बाद में कवर कवर करते हैं जो वास्तव में ऐसा करता है?
मैकेंज़्म

5
@MingDuck मैं आपके सुझाव से सहमत नहीं हूं, और आपके सुझाव में निष्कर्ष का समर्थन करने के लिए तर्क का अभाव है। मैं व्यक्तिगत रूप से फ़ंक्शन पॉइंटर्स पर टाइपफ़ेड का उपयोग करना पसंद नहीं करता, और मुझे लगता है कि यह कोड को स्पष्ट और पढ़ने में आसान बनाता है।
andrewrk

2
@andrewrk: आप पसंद करते हैं void funcA(void(*funcB)(int))और void (*funcA())(), typedef void funcB(); void funcA(funcB)और funcB funcA()? मैं उल्टा नहीं देखता।
मूविंग डक

जवाबों:


746

घोषणा

एक फ़ंक्शन के लिए एक प्रोटोटाइप जो एक फ़ंक्शन पैरामीटर लेता है, निम्न की तरह दिखता है:

void func ( void (*f)(int) );

यह बताता है कि पैरामीटर fएक फंक्शन का पॉइंटर होगा जिसमें voidरिटर्न टाइप होता है और जो सिंगल intपैरामीटर लेता है । निम्न फ़ंक्शन ( print) एक फ़ंक्शन का एक उदाहरण है जिसे funcएक पैरामीटर के रूप में पारित किया जा सकता है क्योंकि यह उचित प्रकार है:

void print ( int x ) {
  printf("%d\n", x);
}

फंक्शन कॉल

फ़ंक्शन पैरामीटर के साथ किसी फ़ंक्शन को कॉल करते समय, पास किया गया मान फ़ंक्शन के लिए सूचक होना चाहिए। इसके लिए फ़ंक्शन के नाम (कोष्ठक के बिना) का उपयोग करें:

func(print);

कॉल करेगा func, इसे प्रिंट फंक्शन पास करेगा।

कार्य शरीर

किसी भी पैरामीटर के साथ, funcअब पैरामीटर के मान तक पहुंचने के लिए फ़ंक्शन बॉडी में पैरामीटर के नाम का उपयोग कर सकते हैं। मान लें कि funcयह फंक्शन लागू करेगा यह संख्या 0-4 से पास किया गया है। ध्यान दें, पहले, लूप सीधे प्रिंट को कॉल करने के लिए कैसा दिखेगा:

for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
  print(ctr);
}

चूँकि funcपैरामीटर की घोषणा यह कहती है कि fवांछित फ़ंक्शन के लिए एक पॉइंटर का नाम है, हम पहले याद करते हैं कि यदि fकोई पॉइंटर है तो *fवह चीज़ है जो इस मामले में f(यानी फ़ंक्शन को इंगित करता printहै)। परिणामस्वरूप, ऊपर दिए गए लूप में प्रिंट की प्रत्येक घटना को प्रतिस्थापित करें *f:

void func ( void (*f)(int) ) {
  for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
    (*f)(ctr);
  }
}

स्रोत


40
आपके पहले और आखिरी कोड के उदाहरणों में, * अनिवार्य नहीं है। फ़ंक्शन पैरामीटर परिभाषा और fफ़ंक्शन कॉल दोनों ही ले सकते हैं fजैसे कि बिना *। यह एक अच्छा विचार हो सकता है जैसा कि आप करते हैं, हालांकि यह स्पष्ट करने के लिए कि पैरामीटर f एक फ़ंक्शन पॉइंटर है। लेकिन यह पठनीयता को काफी नुकसान पहुंचाता है।
गौथियर

5
उदाहरण के लिए देखें [c99, 6.9.1§14]। दोनों निश्चित रूप से सही हैं, मैं सिर्फ विकल्प का उल्लेख करना चाहता था।
गौथियर

6
वास्तव में? टॉप-रेटेड उत्तर typedefफ़ंक्शन पॉइंटर्स के लिए उपयोग करने के लिए एक संदर्भ नहीं देता है ? क्षमा करें, डाउन-वोट करना है।
जोनाथन रेनहार्ट

3
@JonathonReinhart, 'typedef' ऐप्रेक के साथ क्या फायदे होंगे? यह संस्करण हालांकि अधिक साफ दिखता है और अतिरिक्त बयानों का भी अभाव है। यहाँ बहुत ज्यादा स्टार्टर।
अभिनव गौनियाल

3
@JonathonReinhart अच्छी तरह से देखा; यह स्पष्ट रूप से ध्यान में रखा जाना चाहिए कि सूचक टाइपफेड कोड को बाधित करता है और इसलिए इसका उपयोग नहीं किया जाना चाहिए।
एमएम

129

इस सवाल के पास पहले से ही फ़ंक्शन पॉइंटर्स को परिभाषित करने का जवाब है, हालांकि वे बहुत गड़बड़ हो सकते हैं, खासकर यदि आप उन्हें अपने आवेदन के आसपास से गुजरने जा रहे हैं। इस अप्रियता से बचने के लिए मैं आपको सलाह दूंगा कि आप फ़ंक्शन पॉइंटर को कुछ अधिक पठनीय में टाइप करें। उदाहरण के लिए।

typedef void (*functiontype)();

एक फ़ंक्शन की घोषणा करता है जो शून्य देता है और कोई तर्क नहीं लेता है। अब आप कर सकते हैं इस प्रकार के लिए एक फ़ंक्शन पॉइंटर बनाने के लिए:

void dosomething() { }

functiontype func = &dosomething;
func();

एक फ़ंक्शन के लिए जो एक इंट रिटर्न देता है और एक चार लेता है जो आप करेंगे

typedef int (*functiontype2)(char);

और इसका उपयोग करने के लिए

int dosomethingwithchar(char a) { return 1; }

functiontype2 func2 = &dosomethingwithchar
int result = func2('a');

ऐसे पुस्तकालय हैं जो फ़ंक्शन पॉइंटर्स को अच्छे पठनीय प्रकारों में बदलने में मदद कर सकते हैं। बढ़ावा समारोह पुस्तकालय महान है और प्रयास के लायक अच्छी तरह से है!

boost::function<int (char a)> functiontype2;

ऊपर से इतना अच्छा है।


4
यदि आप "फ़ंक्शन पॉइंटर को एक प्रकार में बदलना चाहते हैं", तो आपको बूस्ट लाइब्रेरी की आवश्यकता नहीं है। बस उपयोग करें typedef; यह सरल है और किसी भी अतिरिक्त पुस्तकालयों की आवश्यकता नहीं है।
wizzwizz4

72

C ++ 11 के बाद से आप एक रसीला और सामान्य फैशन में ऐसा करने के लिए कार्यात्मक पुस्तकालय का उपयोग कर सकते हैं । वाक्य रचना है, जैसे,

std::function<bool (int)>

boolएक-तर्क फ़ंक्शन के यहाँ वापसी प्रकार कहाँ है जिसका पहला तर्क प्रकार का है int

मैंने नीचे एक उदाहरण कार्यक्रम शामिल किया है:

// g++ test.cpp --std=c++11
#include <functional>

double Combiner(double a, double b, std::function<double (double,double)> func){
  return func(a,b);
}

double Add(double a, double b){
  return a+b;
}

double Mult(double a, double b){
  return a*b;
}

int main(){
  Combiner(12,13,Add);
  Combiner(12,13,Mult);
}

कभी-कभी, हालांकि, टेम्पलेट फ़ंक्शन का उपयोग करना अधिक सुविधाजनक होता है:

// g++ test.cpp --std=c++11

template<class T>
double Combiner(double a, double b, T func){
  return func(a,b);
}

double Add(double a, double b){
  return a+b;
}

double Mult(double a, double b){
  return a*b;
}

int main(){
  Combiner(12,13,Add);
  Combiner(12,13,Mult);
}

43
प्रश्न C के बारे में है; C ++ यहां लागू नहीं होता है।
सुपर कैट

16
C ++ ( stackoverflow.com/questions/6339970/… ) के लिए प्रश्न यहां संदर्भित है, इसलिए मुझे लगता है कि यह उत्तर लागू है।
mr_T

8
हो सकता है कि C ++ के लिए प्रश्न को यहां संदर्भित न किया जाए क्योंकि यह प्रश्न C. के लिए है
माइकल फुल्टन

5
यह प्रश्न पहले आया जब मैंने "c ++ फंक्शन कॉल को पैरामीटर के रूप में खोजा", इसलिए यह उत्तर परवाह किए बिना यहां अपने उद्देश्य की पूर्ति कर रहा है।
ufoxDan

24

दर्रा एक और कार्य करने के लिए पैरामीटर के रूप में एक समारोह का पता के रूप में नीचे दिखाया गया है

#include <stdio.h>

void print();
void execute(void());

int main()
{
    execute(print); // sends address of print
    return 0;
}

void print()
{
    printf("Hello!");
}

void execute(void f()) // receive address of print
{
    f();
}

फ़ंक्शन पॉइंटर का उपयोग करके हम फ़ंक्शन को पैरामीटर के रूप में भी पास कर सकते हैं

#include <stdio.h>

void print();
void execute(void (*f)());

int main()
{
    execute(&print); // sends address of print
    return 0;
}

void print()
{
    printf("Hello!");
}

void execute(void (*f)()) // receive address of print
{
    f();
}

बहुत अच्छा जवाब, कोड के पूरे ब्लॉक के साथ (एक असंगत गंदगी में सब कुछ टुकड़ा करने के बजाय)। क्या आप दोनों तकनीकों के अंतर के बारे में विस्तार से बता सकते हैं?
राफेल Eyng

5

कार्य समारोह संकेत के रूप में "पारित कर दिया" किया जा सकता है, के अनुसार आईएसओ C11 6.7.6.3p8: " 'के रूप में' 'समारोह प्रकार लौटने' '' समारोह लौटने प्रकार के सूचक 'के लिए समायोजित किया जाएगा' एक पैरामीटर का एक घोषणा , 6.3 में के रूप में .2.1। " उदाहरण के लिए, यह:

void foo(int bar(int, int));

इसके बराबर है:

void foo(int (*bar)(int, int));

आप किस दस्तावेज़ से उद्धृत कर रहे हैं? इसका कोई लिंक?
राफेल Eyng

1
मैं आईएसओ सी 11 मानक से उद्धृत कर रहा हूं।
12

4

आपको एक फ़ंक्शन पॉइंटर पास करना होगा । वाक्य-विन्यास थोड़ा बोझिल है, लेकिन इससे परिचित होते ही यह वास्तव में शक्तिशाली हो जाता है।


-2

यह वास्तव में एक फ़ंक्शन नहीं है, लेकिन यह कोड का एक स्थानीयकृत टुकड़ा है। बेशक यह कोड सिर्फ परिणाम नहीं देता है। यह काम नहीं करेगा यदि बाद के समय में चलाया जाने वाला ईवेंट डिस्पैचर पास कर दिया जाए (जैसा कि परिणाम की गणना अब की जाती है और जब घटना होती है तब नहीं)। लेकिन यह आपके कोड को एक स्थान पर स्थानीय कर देता है अगर वह सब आप करने की कोशिश कर रहे हैं।

#include <stdio.h>

int IncMultInt(int a, int b)
{
    a++;
    return a * b;
}

int main(int argc, char *argv[])

{
    int a = 5;
    int b = 7;

    printf("%d * %d = %d\n", a, b, IncMultInt(a, b));

    b = 9;

    // Create some local code with it's own local variable
    printf("%d * %d = %d\n", a, b,  ( { int _a = a+1; _a * b; } ) );

    return 0;
}

आप केवल एक समारोह में शामिल हो रहे हैं। आप इसके स्थान पर कुछ अन्य फ़ंक्शन कैसे पास करेंगे IncMultInt?
तेजस पेंडसे
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.