আপনি কীভাবে সিটিতে প্যারামিটার হিসাবে কোনও ফাংশনটি পাস করবেন?


615

আমি এমন একটি ফাংশন তৈরি করতে চাই যা ডেটার সেটটিতে প্যারামিটার দ্বারা পাস একটি ফাংশন সম্পাদন করে। আপনি কীভাবে সিটিতে প্যারামিটার হিসাবে কোনও ফাংশনটি পাস করবেন?


12
আপনি যদি ভেরিয়েবল হিসাবে ফাংশন / অ্যারে ব্যবহার করে থাকেন তবে সর্বদা ব্যবহার করুন typedef
মাকিং হাঁস


ফাংশনের নামটি ফাংশনের পন্টার হওয়া উচিত। বেশিরভাগ লোক সি বা কভারসোর্ট শিখছেন তাড়াতাড়ি বা পরে যা ঠিক এটি করে?
ম্যাকেনজম

5
@ মুভিংডাক আমি আপনার পরামর্শের সাথে একমত নই এবং আপনার পরামর্শে উপসংহারটি সমর্থন করার পক্ষে যুক্তির অভাব রয়েছে। আমি ব্যক্তিগতভাবে ফাংশন পয়েন্টারগুলিতে কখনও টাইপিডেফ ব্যবহার করতে পছন্দ করি না এবং আমি মনে করি এটি কোডটি আরও পরিষ্কার এবং আরও সহজ করে তোলে।
অ্যান্ড্রুর্ক

2
@ অ্যান্ড্রুর্ক: আপনি পছন্দ করেন void funcA(void(*funcB)(int))এবং পছন্দ void (*funcA())()করেন typedef void funcB(); void funcA(funcB)এবং funcB funcA()? আমি উল্টোটা দেখতে পাচ্ছি না
মাকিং হাঁস

উত্তর:


746

ঘোষণা

কোনও ফাংশনের প্যারামিটার গ্রহণ করে এমন কোনও ক্রিয়াকলাপের নীচের মত দেখতে:

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

এটি সূচিত করে যে পরামিতি fকোনও ফাংশনের পয়েন্টার হবে যার voidরিটার্ন টাইপ রয়েছে এবং যা একক intপরামিতি নেয় takes নিম্নলিখিত ফাংশন ( 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* ছাড়াই নিতে পারে । প্যারামিটার এফ একটি ফাংশন পয়েন্টার এটি স্পষ্ট করে তুলতে এটি করার মতো এটি করা ভাল ধারণা হতে পারে। তবে এটি বেশিরভাগ সময় পঠনযোগ্যতাতে ব্যথা করে।
গৌথিয়ার

5
উদাহরণের জন্য [c99, 6.9.1§14] দেখুন। উভয় অবশ্যই সঠিক, আমি কেবল বিকল্পটি উল্লেখ করতে চেয়েছিলাম।
গৌথির

6
সত্যি? শীর্ষ রেট করা উত্তরটি typedefফাংশন পয়েন্টারগুলির জন্য কোনও একক রেফারেন্স তৈরি করে না ? দুঃখিত, ভোট দিতে হবে।
জোনাথন রেইনার্ট

3
@ জোনাথনরেইনহার্ট, 'টাইপিডেফ' উপকরণের সুবিধা কী হবে? যদিও এই সংস্করণটি আরও পরিষ্কার দেখাচ্ছে এবং অতিরিক্ত বিবৃতিও নেই cks বেশ সুন্দর এখানে।
অভিনব গৌনিয়াল

3
পুনঃটুইট করুন এটি স্পষ্টভাবে লক্ষ করা উচিত যে পয়েন্টার টাইপডেফস কোডটি আবদ্ধ করে এবং তাই এটি ব্যবহার করা উচিত নয়।
এমএম

129

এই প্রশ্নের ফাংশন পয়েন্টার সংজ্ঞায়নের জন্য ইতিমধ্যে উত্তর রয়েছে, তবে তারা খুব অগোছালো হয়ে উঠতে পারে, বিশেষত যদি আপনি তাদের নিজের অ্যাপ্লিকেশনটির চারপাশে চলে যাচ্ছেন। এই অপ্রীতিকরতা এড়াতে আমি আপনাকে সুপারিশ করব যে আপনি ফাংশন পয়েন্টারটি আরও পাঠযোগ্য into উদাহরণ স্বরূপ.

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

যেহেতু সি ++ 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
প্রশ্নটি সি সম্পর্কে; সি ++ এখানে প্রয়োগ হয় না।
সুপার ক্যাট

16
সি ++ ( স্ট্যাকওভারফ্লো / প্রশ্ন / 6339970/… ) এর জন্য প্রশ্নটি এখানে উল্লেখ করা হয়েছে, সুতরাং আমার মনে হয় এই উত্তরটি ঠিক আছে।
এমআর_আর

8
হয়তো সি ++ এর জন্য প্রশ্নটি এখানে উল্লেখ করা উচিত নয় কারণ এই প্রশ্নটি সি।
মাইকেল ফুলটন

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();
}

পুরো ব্লক কোড সহ (খুব অজানা জগাখিচুড়ি করে সমস্ত কিছু টুকরো টুকরো করার পরিবর্তে) খুব সুন্দর উত্তর। আপনি উভয় প্রযুক্তির পার্থক্য বিস্তারিতভাবে বলতে পারেন?
রাফায়েল আইং

5

ফাংশন পয়েন্টার হিসাবে ফাংশনগুলি "পাস" করা যায়, আইএসও সি 11 6.7.6.3p8 অনুসারে: " 'ফাংশন রিটার্নিং টাইপ' 'হিসাবে একটি পরামিতি ঘোষণাকে' 'ফাংশন রিটার্নিং টাইপ' 'তে পয়েন্টারের সাথে সামঞ্জস্য করা হবে , 6.3 হিসাবে .2.1। "। উদাহরণস্বরূপ, এটি:

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

এর সমতুল্য:

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

আপনি কোন দলিল থেকে উদ্ধৃতি দিচ্ছেন? এর সাথে কোনও লিঙ্ক?
রাফায়েল আইং

1
আমি আইএসও সি 11 স্ট্যান্ডার্ড থেকে উদ্ধৃত করছি।
ডপপেলহেথেন

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?
তেজাস পেন্ডসে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.