खोज…


परिचय

फ़ंक्शन पॉइंटर्स पॉइंटर्स होते हैं जो डेटा प्रकारों के बजाय फ़ंक्शंस को इंगित करते हैं। उन्हें रन-टाइम पर फ़ंक्शन में परिवर्तनशीलता की अनुमति देने के लिए उपयोग किया जा सकता है।

वाक्य - विन्यास

  • रिटर्न टाइप (* नाम) (पैरामीटर)

  • टाइपडिफ रिटर्न टाइप (* नाम) (पैरामीटर)

  • टाइपडिफ रिटर्न टाइप नाम (पैरामीटर);
    नाम नाम;

  • टाइपडिफ रिटर्न टाइप नाम (पैरामीटर);
    typedef Name * NamePtr;

एक फंक्शन पॉइंटर को असाइन करना

#include <stdio.h>

/* increment: take number, increment it by one, and return it */
int increment(int i)
{
    printf("increment %d by 1\n", i);
    return i + 1;
}

/* decrement: take number, decrement it by one, and return it */
int decrement(int i)
{
    printf("decrement %d by 1\n", i);
    return i - 1;
}

int main(void)
{
    int num = 0;          /* declare number to increment */
    int (*fp)(int);       /* declare a function pointer */

    fp = &increment;      /* set function pointer to increment function */
    num = (*fp)(num);     /* increment num */
    num = (*fp)(num);     /* increment num a second time */

    fp = &decrement;      /* set function pointer to decrement function */
    num = (*fp)(num);     /* decrement num */
    printf("num is now: %d\n", num);
    return 0;
}

एक फंक्शन से रिटर्निंग फंक्शन पॉइंटर्स

#include <stdio.h>

enum Op
{
  ADD = '+',
  SUB = '-',
};


/* add: add a and b, return result */    
int add(int a, int b)
{
    return a + b;
}

/* sub: subtract b from a, return result */
int sub(int a, int b)
{
    return a - b;
}

/* getmath: return the appropriate math function */
int (*getmath(enum Op op))(int,int)
{
    switch (op)
    {
        case ADD:
            return &add;
        case SUB:
            return &sub;
        default:
            return NULL;
    }
}

int main(void)
{
    int a, b, c;
    int (*fp)(int,int);

    fp = getmath(ADD);

    a = 1, b = 2;
    c = (*fp)(a, b);
    printf("%d + %d = %d\n", a, b, c);
    return 0;
}

सर्वोत्तम प्रथाएं

टंकण का उपयोग करना

हर बार फ़ंक्शन पॉइंटर को हाथ से घोषित करने के बजाय एक typedef का उपयोग करना आसान हो सकता है।

फंक्शन पॉइंटर के लिए typedef घोषित करने का सिंटैक्स है:

typedef returnType (*name)(parameters);

उदाहरण:

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

तुलना - दो तत्वों के लिए एक तुलना फ़ंक्शन जो एक प्रकार्य फ़ंक्शन को आपूर्ति की जानी है।

"तुलना" से वापसी की उम्मीद है यदि दो तत्वों को समान माना जाता है, तो एक सकारात्मक मूल्य यदि पहले तत्व पारित हो गया है तो बाद के तत्व की तुलना में कुछ अर्थों में "बड़ा" है और अन्यथा फ़ंक्शन एक नकारात्मक मान लौटाता है (जिसका अर्थ है कि पहला तत्व है उत्तरार्द्ध की तुलना में "कम"।

बिना typedef हम एक फ़ंक्शन पॉइंटर को निम्न तरीके से फ़ंक्शन के तर्क के रूप में पास करेंगे:

void sort(int (*compare)(const void *elem1, const void *elem2)) { 
    /* inside of this block, the function is named "compare" */
}

एक typedef साथ, हम लिखेंगे:

typedef int (*compare_func)(const void *, const void *);

और फिर हम इस sort के फ़ंक्शन हस्ताक्षर को बदल सकते हैं:

void sort(compare_func func) { 
    /* In this block the function is named "func" */
}

sort की दोनों परिभाषाएं फॉर्म के किसी भी फ़ंक्शन को स्वीकार करती हैं

int compare(const void *arg1, const void *arg2) {
    /* Note that the variable names do not have to be "elem1" and "elem2" */
}

फ़ंक्शन पॉइंटर्स एकमात्र ऐसी जगह है जहां आपको प्रकार की पॉइंटर संपत्ति को शामिल करना चाहिए, उदाहरण के लिए typedef struct something_struct *something_type जैसे प्रकारों को परिभाषित करने का प्रयास न करें। यह उन सदस्यों के साथ एक संरचना के लिए भी लागू होता है, जिन्हें सीधे एपीआई कॉलर्स द्वारा एक्सेस नहीं किया जाता है, उदाहरण के लिए stdio.h FILE प्रकार (जो अब आप देखेंगे कि सूचक नहीं है)।

संदर्भ बिंदुओं को लेना।

एक फ़ंक्शन पॉइंटर को लगभग हमेशा एक उपयोगकर्ता-प्रदत्त शून्य * एक संदर्भ पॉइंटर के रूप में लेना चाहिए।

उदाहरण

/* function minimiser, details unimportant */
double findminimum( double (*fptr)(double x, double y, void *ctx), void *ctx)
{
    ...
    /* repeatedly make calls like this */
    temp = (*fptr)(testx, testy, ctx);
}

/* the function we are minimising, sums two cubics */
double *cubics(double x, double y, void *ctx)
{
    double *coeffsx = ctx;
    double *coeffsy = coeffx + 4;

    return coeffsx[0] * x * x * x + coeffsx[1] * x * x + coeffsx[2] * x + coeffsx[3] +
           coeffsy[0] * y * y * y + coeffsy[1] * y * y + coeffsy[2] * y + coeffsy[3];

} 

void caller()
{
    /* context, the coefficients of the cubics */
    double coeffs[8] = {1, 2, 3, 4, 5, 6, 7, 8};
    double min;

    min = findminimum(cubics, coeffs);       
}

संदर्भ सूचक का उपयोग करने का मतलब है कि अतिरिक्त मापदंडों को इंगित किए गए फ़ंक्शन में हार्ड-कोड किए जाने की आवश्यकता नहीं है, या उपयोग ग्लोबल्स की आवश्यकता है।

लायब्रेरी फ़ंक्शन qsort() इस नियम का पालन नहीं करता है, और एक अक्सर तुच्छ तुलना कार्यों के लिए संदर्भ के बिना दूर हो सकता है। लेकिन कुछ अधिक जटिल के लिए, संदर्भ सूचक आवश्यक हो जाता है।


यह सभी देखें

कार्य संकेत

परिचय

char और int तरह, एक फ़ंक्शन सी की एक मूलभूत विशेषता है। जैसे कि, आप एक को एक पॉइंटर घोषित कर सकते हैं: जिसका अर्थ है कि आप दूसरे फ़ंक्शन को कॉल कर सकते हैं ताकि वह अपना काम करने में मदद कर सके। उदाहरण के लिए, यदि आपके पास एक graph() फ़ंक्शन है जो एक ग्राफ़ प्रदर्शित करता है, तो आप ग्राफ़ में graph() में किस फ़ंक्शन को पास कर सकते हैं graph()

// A couple of external definitions to make the example clearer
extern unsigned int screenWidth;
extern void plotXY(double x, double y);

// The graph() function.
// Pass in the bounds: the minimum and maximum X and Y that should be plotted.
// Also pass in the actual function to plot.
void graph(double minX, double minY,
           double maxX, double maxY,
           ???? *fn) {            // See below for syntax

    double stepX = (maxX - minX) / screenWidth;
    for (double x=minX; x<maxX; x+=stepX) {

        double y = fn(x);         // Get y for this x by calling passed-in fn()

        if (minY<=y && y<maxY) {
            plotXY(x, y);         // Plot calculated point
        } // if
    } for
} // graph(minX, minY, maxX, maxY, fn)

प्रयोग

तो उपरोक्त कोड आपके द्वारा दिए गए किसी भी फ़ंक्शन को ग्राफ़ करेगा - जब तक कि फ़ंक्शन कुछ मानदंडों को पूरा करता है: अर्थात्, कि आप एक double पास करते हैं और एक double आउट प्राप्त करते हैं। ऐसे कई कार्य हैं - sin() , cos() , tan() , exp() आदि - लेकिन कई ऐसे हैं जो graph() जैसे graph() ही नहीं हैं!

वाक्य - विन्यास

तो आप कैसे निर्दिष्ट करते हैं कि आप किन कार्यों को graph() में पास कर सकते हैं graph() और कौन से आप नहीं कर सकते हैं? पारंपरिक तरीका एक वाक्यविन्यास का उपयोग करना है जो पढ़ने या समझने में आसान नहीं हो सकता है:

double (*fn)(double); // fn is a pointer-to-function that takes a double and returns one

उपरोक्त समस्या यह है कि दो चीजें एक ही समय में परिभाषित करने की कोशिश कर रही हैं: फ़ंक्शन की संरचना, और तथ्य यह है कि यह एक सूचक है। तो, दो परिभाषाओं को विभाजित करें! लेकिन typedef का उपयोग करके, एक बेहतर वाक्यविन्यास (पढ़ने और समझने में आसान) प्राप्त किया जा सकता है।

फ़ंक्शन पॉइंटर्स लिखने के लिए Mnemonic

सभी C फ़ंक्शंस रियलिटी पॉइंटर्स में प्रोग्राम मेमोरी में एक स्पॉट पर होते हैं जहां कुछ कोड मौजूद होता है। एक फ़ंक्शन पॉइंटर का मुख्य उपयोग अन्य कार्यों (या कक्षाओं और वस्तुओं को अनुकरण करने के लिए) पर "कॉलबैक" प्रदान करना है।

किसी फ़ंक्शन का सिंटैक्स, जैसा कि इस पृष्ठ पर और नीचे दिया गया है:

रिटर्न टाइप (* नाम) (पैरामीटर)

एक फ़ंक्शन पॉइंटर परिभाषा लिखने के लिए एक एमनोमिक निम्नलिखित प्रक्रिया है:

  1. एक सामान्य फ़ंक्शन घोषणापत्र लिखकर शुरू करें: returnType name(parameters)
  2. पॉइंटर सिंटैक्स के साथ फ़ंक्शन नाम लपेटें: returnType (*name)(parameters)

मूल बातें

जैसे आपके पास एक int , char , float , array / string , स्ट्रक्चर आदि के लिए एक पॉइंटर हो सकता है - आप एक फंक्शन के लिए एक पॉइंटर रख सकते हैं।

पॉइंटर की घोषणा करने से फ़ंक्शन का रिटर्न मान, फ़ंक्शन का नाम और इसे प्राप्त होने वाले तर्क / पैरामीटर का प्रकार होता है

कहो कि आपके पास निम्न फ़ंक्शन घोषित और आरंभिक हैं:

int addInt(int n, int m){
    return n+m;
}

आप इस फ़ंक्शन के लिए एक पॉइंटर घोषित और आरंभ कर सकते हैं:

int (*functionPtrAdd)(int, int) = addInt; // or &addInt - the & is optional

यदि आपके पास एक शून्य फ़ंक्शन है तो यह इस तरह दिख सकता है:

void Print(void){
    printf("look ma' - no hands, only pointers!\n");
}

तब सूचक को यह घोषित करना होगा:

void (*functionPtrPrint)(void) = Print;

फ़ंक्शन तक पहुँचने के लिए पॉइंटर की आवश्यकता होती है:

sum = (*functionPtrAdd)(2, 3); //will assign 5 to sum
(*functionPtrPrint)(); //will print the text in Print function

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

typedef int (*ptrInt)(int, int);

int Add(int i, int j){
    return i+j;
}

int Multiply(int i, int j){
    return i*j;
}

int main()
{
    ptrInt ptr1 = Add;
    ptrInt ptr2 = Multiply;

    printf("%d\n", (*ptr1)(2,3)); //will print 5
    printf("%d\n", (*ptr2)(2,3)); //will print 6
    return 0;
}

आप फ़ंक्शन-पॉइंटर्स का एक सरणी भी बना सकते हैं। यदि सभी बिंदु समान "संरचना" के हैं:

int (*array[2]) (int x, int y); // can hold 2 function pointers
array[0] = Add;
array[1] = Multiply;

आप यहां और यहां और अधिक जान सकते हैं।

विभिन्न प्रकारों के फ़ंक्शन-पॉइंटर्स की एक सरणी को परिभाषित करना भी संभव है, हालांकि जब आपको विशिष्ट फ़ंक्शन तक पहुंचने के लिए कास्टिंग की आवश्यकता होती है। आप यहां और जान सकते हैं।



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow