सी फ़ंक्शन पॉइंटर्स में अधिक पैरामीटर पास करना

मान लें कि मैं एक शतरंज कार्यक्रम बना रहा हूं। मेरे पास एक समारोह है

void foreachMove( void (*action)(chess_move*), chess_game* game); 

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

chess_move getNextMove(chess_game* game, int depth){
  //for each valid move, determine how good the move is
  foreachMove(moveHandler, game);
}

void moveHandler(chess_move* move){
  //uh oh, now I need the variables "game" and "depth" from the above function
}

फ़ंक्शन पॉइंटर को फिर से परिभाषित करना इष्टतम समाधान नहीं है। ForeachMove फ़ंक्शन बहुमुखी है और कोड संदर्भ में कई अलग-अलग स्थान हैं। उन संदर्भों में से प्रत्येक के लिए उनके फ़ंक्शन को अपडेट करने के लिए यह समझ में नहीं आता है कि उन पैरामीटर को शामिल करने के लिए जिन्हें उनकी आवश्यकता नहीं है।

मैं एक ऐसे फ़ंक्शन पर अतिरिक्त पैरामीटर कैसे पास कर सकता हूं जिसे मैं पॉइंटर के माध्यम से कॉल कर रहा हूं?

0
ro fr bn

8 उत्तर

अतिरिक्त तर्क लेने के लिए आपको फ़ंक्शन पॉइंटर को फिर से परिभाषित करने की आवश्यकता होगी।

void foreachMove( void (*action)(chess_move*, int), chess_game* game )
0
जोड़ा

Use a typedef for the function pointer. See my answer for this question

0
जोड़ा

मैं शून्य प्रविष्टि की एक सरणी का उपयोग करने का सुझाव दूंगा, अंतिम प्रविष्टि हमेशा शून्य के साथ। कहें कि आपको 3 पैरामीटर चाहिए जो आप कर सकते हैं:

void MoveHandler (void** DataArray)
{
   //data1 is always chess_move
    chess_move data1 = DataArray[0]? (*(chess_move*)DataArray[0]) : NULL; 
   //data2 is always float
    float data1 = DataArray[1]? (*(float*)DataArray[1]) : NULL; 
   //data3 is always char
    char data1 = DataArray[2]? (*(char*)DataArray[2]) : NULL; 
    //etc
}

void foreachMove( void (*action)(void**), chess_game* game);

और फिर

chess_move getNextMove(chess_game* game, int depth){
    //for each valid move, determine how good the move is
    void* data[4];
    data[0] = &chess_move;
    float f1;
    char c1;
    data[1] = &f1;
    data[2] = &c1;
    data[3] = NULL;
    foreachMove(moveHandler, game);
}

यदि सभी पैरामीटर एक ही प्रकार के होते हैं तो आप शून्य * सरणी से बच सकते हैं और आपको जो भी प्रकार की आवश्यकता है, उसे केवल एक पूर्ण-समाप्त सरणी भेज सकते हैं।

0
जोड़ा

एंटोनियो को +1। अतिरिक्त पैरामीटर स्वीकार करने के लिए आपको अपने फ़ंक्शन पॉइंटर घोषणा को बदलने की आवश्यकता है।

इसके अलावा, कृपया शून्य पॉइंटर्स या (विशेष रूप से) शून्य पॉइंटर्स के सरणी को पार करना प्रारंभ न करें। यह सिर्फ परेशानी के लिए पूछ रहा है। यदि आप शून्य पॉइंटर्स को गुजरना शुरू करते हैं, तो आपको इंगित करने के लिए कुछ प्रकार का संदेश भी देना होगा कि पॉइंटर प्रकार क्या है (या प्रकार हैं)। यह तकनीक शायद ही कभी उपयुक्त है।

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

0
जोड़ा

यदि आप कुछ सी ++ का उपयोग करने के इच्छुक हैं, तो आप "फ़ंक्शन ऑब्जेक्ट" का उपयोग कर सकते हैं:

struct MoveHandler {
    chess_game *game;
    int depth;

    MoveHandler(chess_game *g, int d): game(g), depth(d) {}

    void operator() (chess_move*) {
        //now you can use the game and the depth
    }
};

और एक टेम्पलेट में अपना foreachMove चालू करें:

template 
void foreachMove(T action, chess_game* game);

और आप इसे इस तरह से कॉल कर सकते हैं:

chess_move getNextMove(chess_game* game, int depth){
    //for each valid move, determine how good the move is
    foreachMove(MoveHandler(game, depth), game);
}

लेकिन यह MoveHandler के आपके अन्य उपयोगों को बाधित नहीं करेगा।

0
जोड़ा

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

http://publications.gbdirect.co.uk/c_book/chapter9/stdarg। एचटीएमएल

बस एक एफवाईआई, लिंक में उदाहरण कोड के बारे में: उनके पास कुछ जगह हैं? एन तर्क? और दूसरों को यह है? n_args? अंडरस्कोर के साथ। वे सभी अंडरस्कोर होना चाहिए। मैंने सोचा कि वाक्यविन्यास थोड़ा मजाकिया लग रहा था जब तक मुझे एहसास हुआ कि उन्होंने कुछ जगहों पर अंडरस्कोर गिरा दिया था।

0
जोड़ा

एक अन्य विकल्प फंक्शन प्रोटोटाइप के बजाय chess_move संरचना को संशोधित करना होगा। संरचना को संभवतः पहले से ही एक ही स्थान पर परिभाषित किया गया है। सदस्यों को संरचना में जोड़ें, और किसी भी कॉल का उपयोग करने से पहले उचित डेटा के साथ संरचना को भरें।

0
जोड़ा

अगर मैं यह सही पढ़ रहा हूं, तो मैं सुझाव दूंगा कि आपके कार्य को एक तर्क के रूप में एक संरचना में पॉइंटर लेना है। फिर, जब आपकी आवश्यकता होती है तो आपकी संरचना में "गेम" और "गहराई" हो सकती है, और जब उन्हें आवश्यकता नहीं होती है तो उन्हें केवल 0 या नल पर सेट करें।

उस समारोह में क्या चल रहा है? क्या आपके पास एक सशर्त है जो कहता है,

if (depth > -1) //some default
  {
  //do something
  }

क्या फ़ंक्शन हमेशा "गेम" और "गहराई" की आवश्यकता है? फिर, उन्हें हमेशा तर्क होना चाहिए, और यह आपके प्रोटोटाइप में जा सकता है।

क्या आप इंगित कर रहे हैं कि फ़ंक्शन को कभी-कभी "गेम" और "गहराई" की आवश्यकता होती है? खैर, शायद दो कार्य करें और जब आपको आवश्यकता हो तो प्रत्येक का उपयोग करें।

लेकिन, तर्क के रूप में एक संरचना होने के नाते शायद सबसे आसान बात है।

0
जोड़ा