function pointer in C

C programming language मध्ये असे काही topics आहेत कि ते अभ्यासक्रमात घेतले जात नाहीत अथवा इतक्या brief मध्ये संपवले जातात कि त्या topics विषयी अज्ञान किंवा भिती अथवा दोनही कायमच्या रहातात. function pointer हा अशाच प्रकारचा एक टॉपीक.  Typecast, bit fields, union, bit operators पेक्षा सुद्धा जास्त सापत्नपणाची (Step-motherly treatment) वागणूक मिळालेल्या या टॉपीकविषयी मी लिहीणार आहे. कारण C++ मध्ये virtual function या महत्वाच्या chapter चे fundamental concepts या topic मध्ये दडून बसलेले आहेत.

हव तर pointer म्हणजे काय हे एकदम सोप्प्या भाषेत समजावून घ्यायच असेल तर हा व्हिडीओ पहाच

प्रथम integer pointer, character pointer, float pointer या सारखे साधे pointer वापरत गेले कि एव्हाना गुंतागुंत झालेली असते.  त्या नंतर भरीस भर म्हणून structure pointer, string pointer हे वेगवेगळे शब्द कानावर पडतात. शेवटी file pointer म्हणजे आता बस्स…! अशी अवस्था होते व या सगळ्या धामधुमीत function pointer दुर्लक्षीला जातो तो कायमचाच.

function pointer

function pointer

आता आपल्याला हे माहीत आहे कि प्रोग्रॅम लिहून, कंपाइल व रन करतांना मेन मेमरीमध्येच म्हणजेच Data Segment variables व Code Segment मध्ये compiled व executable code ठेवला जातो. म्हणजेच variables साठी जशी मेमरी दिली जाते त्या प्रमाणे functions साठी सुद्धा memory block दिले जातात. आणी मेमरी आली म्हणजे त्याचा address हा आलाच.

आता या फंक्शनचा address स्टोअर करायला अर्थातच pointer लागणार व त्यालाच function pointer म्हणतात. आणी हे function pointer declare करण्याचे प्रकरणच जरा confusing असल्यासारखे आहे. पण तेच तर मी सोप्या पद्धतीने सांगणार आहे. समजा आपण एक छोटासा प्रोग्रॅम लिहीला. जसे की

#include<stdio.h>
void printmessage( );
int main( )
{

printmessage( );
printf(“Address of function = %un”,printmessage);
return 0;

}

void printmessage( )
{

printf(“In function printmessagen”);

}

या ठिकाणी main function मधील printf function मध्ये printmessage असे argument आहे. आपणच लिहीलेल्या user defined function चे फक्त नाव लिहीले आहे. हा प्रोग्रॅम कंपाइल व रन केला तर तुम्हाला जे output मिळते ते म्हणजे printmessage या फंक्शनचा तो memory मधील address असतो. Array चे नाव म्हणजे array च्या पहील्या element चा address असतो त्या प्रमाणेच printmessage या function च्या नावामध्ये function चा address असतो. त्याच प्रमाणे तुम्ही main function चा address सुद्धा print करू शकता.

आता आपण अजून एक साधा प्रोग्रॅम लिहू व त्या नंतर पाहूया हे function pointer काय प्रकरणं आहे ते…

#include<stdio.h>
void display();
int main()
{

int x;
static int y;
int *ptr;
void (*ptr_to_display)();

ptr_to_display = display;

(*ptr_to_display)( );

ptr = (int*) malloc(sizeof(int));
printf(“Address of x = %un”,&x);
printf(“Address of y = %un”,&y);
printf(“memory given by ptr = %un”,ptr);
printf(“Address of display function = %un”,display);
printf(“Address of main function = %un”,main);
printf(“Address of printf function = %un”,printf);
printf(“Address of scanf function = %un”,scanf);
free(ptr);

}
void display()
{

printf(“In display functionn”);

}

हा प्रोग्रॅम तुम्ही compile व रन केला तर तुम्हाला

  • x या auto variable चा stack वरील
  • y या static variable चा static memory वरील
  • ptr ला dynamic memory allocation ने केलेल्या heap वरील memory चा addresses मिळतील
  • तसेच तुम्हाला printf, scanf, main या library functions चे आणी display या user defined functions चे memory addresses मिळतील.

या ठिकाणी void (*ptr_to_display) ( ); असे एक declaration केले आहे ते function pointer चे declaration आहे व हेच confusing आहे. म्हणून आपण त्याचे dissection करूया.

  1. आपल्याला display या फंक्शनचा address store करायचा आहे व त्याचा return type void आहे म्हणून आपण एक फंक्शन पॉइंटर declaration void असे सुरू केले आहे.
  2. इतर pointer variable ला नाव असते त्याप्रमाणे या variable चे नाव ptr_to_display असे आहे
  3. ते pointer variable असल्यामुळे त्याच्या मागे * जोडला आहे.
  4. आता या *ptr_to_display च्या दोनही बाजूला round brackets आहेत व त्यामुळेच compiler ला हा function pointer आहे असे कळते. व हाच सर्वात कळीचा मुद्दा आहे कारण जर round brackets टाकले नाहीत तर मात्र declaration void *ptr_to_display असे होइल व त्याचा अर्थ ptr_to_display हा void pointer आहे असा होतो.
  5. त्या नंतर pair of round brackets आहेत ते म्हणजे  ज्या function चा pointer करायचा त्या function च्या arguments साठी असते. या ठिकाणी display function arguments घेत नसल्यामुळे brackets empty आहेत.

आता हे वरील स्टेटमेंट एकाच वाक्यात सांगायचे असेल तर “ptr_to_display हा no arguments घेणाऱ्या व void return करणाऱ्या  function चा pointer आहे” असे सांगता येइल.

त्यामुळेच ptr_to_display = display; या assignment स्टेटमेंट मुळे display function चा address ptr_to_display या function pointer मध्ये store होइल.

pointer indirection operator वापरुन जसे pointer ज्या ठिकाणी point करत आहे त्या ठिकाणचे contents access करता येतात त्याच प्रमाणे आपण function pointer वापरुन function ची मेमरी access करणे किंवा function call करण्याची प्रक्रिया सुद्धा करता येते. जसे की…

त्या पुढील स्टेटमेंट म्हणजेच (*ptr_to_display) ( ); actually display function call करण्याचे काम करेल. अर्थात तुम्ही ptr_to_display( ); असे लिहीले तरी सुद्धा display function invoke होतेच.

इतके उद्योग करून याचा उपयोग काय असा प्रश्न साहजीकच पडतो. पण मेमरी बरोबर खेळणे हीच तर C language ची खासीयत आहे. त्यामुळे resident memory programs लिहीण्यासाठी, virus लिहीण्यासाठी, आणी anti-virus लिहीण्यासाठी function pointer चा सर्रास वापर केला जातो.  

void main

int main

#include<stdio.h>
#include<conio.h>
void main()
नवशिका C Programmer कोणताही C चा कोड लिहीतांना त्याच्या वरील ३ lines चा कोड हक्काच्या असतात….! फरक इतकाच तो programmer student जर gcc वापरत असेल तर  तो  #include<conio.h> लिहीणार नाही. आणी शिक्षकांनी सांगीतले आहे किंवा शेजारच्या मित्रांने किंवा मैत्रीणींने लिहीले आहे हे पाहीले तर मग त्याने int main() लिहीलेले असते…

#include<stdio.h>
int main( )
{

………….
………….
………….
return (EXIT_SUCCESS);

}

C programming language हि खरं तर Procedure Oriented Programming वर आधारीत आहे. त्यामुळे लायब्ररी मधील अथवा user defined functions कॉलनेच प्रोग्रॅमचा काही भाग व्यापलेला असतो. या संदंर्भात काही महत्वाचे प्रश्न उपस्थित होतात…

१. मेनमधून जर फंक्शन्स कॉल होत असतील तर मेन सुद्धा एक फंक्शन आहे त्याला कॉल करण्याचे काम कोण करते?

२. मेन पुर्वी void किंवा int असते ते काय असते?

३. मेन पुर्वी void अथवा int या पैकी काय लिहावे?


www.cmarathionline.com

मेन हे इतर फंक्शंन्स प्रमाणेच एक फंक्शन आहे. फरक इतकाच कि मेन कॉल करण्याचे काम operating system करते. अर्थातच इतर फंक्शंन्स च्या नावा मागे जो शब्द असतो त्याप्रमाणेच int अथवा void हा मेन फंक्शनचा return type असतो. Operating System ने जर main function ला कॉल करते तर main function execute झाल्यानंतर operating system ला acknowledgement देणे हे main function ची नैतिक जबाबदारी आहे. अर्थात नैतिक जबाबदाऱ्या या अनेक वेळा पाळल्या जात नाहीत त्याच प्रमाणे main function लिहीतांना सुद्धा void लिहून ती टाळल्याप्रमाणेच आहे.

Good Programming Practice तसेच ISO C च्या documentation नुसार main function चा return type हा int लिहीणे जरूरी आहे. जर प्रोग्रॅम successfully run झाला तर मेन फंक्शन 0 (Zero) return करते आणी जर काही अडचणी आल्या तर मेन फंक्शन non zero value return करते असे convention आहे.

C99 standard प्रमाणे return 0 असे स्टेटमेंट लिहीण्याऐवजी return (EXIT_SUCCESS) हे स्टेटमेंट जास्त सोयीचे समजले जाते कारण या प्रकारे प्रोग्रॅमची portability वाढते. EXIT_SUCCESS आणी EXIT_FAILURE हे दोन macros असून stdlib.h या library file मध्ये define करून ठेवले आहेत. शिवाय हे macro लिहील्यांने program चे understanding सुद्धा चांगल्या पद्धतीने होते.

Beginner C Programmers ना void main असे लिहीण्याची सवय जरी लागली तरी कालांतराने प्रयत्न करून int main या सवयीकडॆ वळणे उत्तम….!

कंपायलर नुसार काहवेळा मिळणाऱ्या warnings बदलू शकतात जसे की काही कंपायलरला तुम्ही int main लिहीले आणी शेवटी return 0 अथवा return (EXIT_SUCCESS) लिहीले नाही तरी warning अथवा error मिळणार नाही कारण हे सर्व जबाबदारी जरी तुम्ही पार पाडली नाही तरी कंपायलर टाळत नाही….!

या शिवाय जर command line arguments पाठवण्याची शक्यता असेल तर त्या बाबतीत main function हे

int main(int argc, char* argv[ ]) असे असते. पण या बद्द्ल मी स्वतंत्र पोस्ट करेन.

Function Prototype

Prototype या इंग्रजी शब्दाचा नेमका अर्थ कळाला तर function prototype चे महत्व आणी अर्थ नक्की कळेल. A prototype is an early sample, model or release of a product built to test a concept or process. In C we write prototype of function.

कोणतेही फंक्शन जर प्रोग्रॅमर कॉल करणार असेल तर फंक्शन कॉल करण्यापुर्वी कंपायलरला त्याची पुर्वसुचना असायला हवी. त्या दृष्टीने कंपायलर तयारीत रहातो. दररोजच्या आयुष्यातील अनेक घटनांपैकी काही घटनांची पुर्वसुचना मिळाली तर त्यांना सामोरे जाण्यासाठी प्रमाणे आपल्याला योग्य प्रकारे तयारी करायला लागते तसाच हा प्रकार आहे.

समजा तुम्ही दोन integer constants आणी एक real constant ची बेरीज करण्याचे फंक्शन लिहीले आहे. तर मग त्याचा प्रोटोटाइप

float addnums(int,int,float); असा असू शकेल…

प्रोटोटाइप मध्ये इतक्या प्रकारची माहीती कंपायलर ला मिळते
१. जे फंक्शन कॉल करणार आहात त्याचे नाव
२. कीती argument फंक्शन घेणार आहे (त्याचा नंबर नसतो)
३. प्रत्येक argument चा डेटाटाइप
४. फंक्शनचा return type

वरील फंक्शन मध्ये
१. addnums नावाचे फंक्शन कॉल करण्याची शक्यता आहे
२. फंक्शन ३ arguments घेत आहे
३. पहीले व दुसरे argument integer असून तिसरे argument float आहे
४. फंक्शन float return करणार आहे.

आपण काही युझर डिफाइंड फंक्शन इतर हेडर फाइल्स मध्ये लिहीली असतील तर ती फाइल main function पुर्वी include करायला लागेल.
त्या प्रमाणेच आपण कंपायलरच्या लायब्ररी मधील जी built in functions call करतो उदा. printf(), scanf(), getch(), clrascr() या फंक्शन्स चे prototypes stdio.h, conio.h इत्यादी header फाइल्स मध्ये असतात. म्हणूनच या फाइल्स main पुर्वी include केल्या जातात.

उत्सुकता म्हणून stdio.h अथवा conio.h या फाइल्स तुम्ही open करून पाहू शकता.

C मध्ये prototype लिहीणे mandatory नसले तरी prototype लिहीण्याची practice हि Good Programming Practice समजली जाते

If you are interested in learning C programming language in audio visual format then visit the link http://www.cmarathionline.com/importance-of-mother-tongue/