Friday, June 10, 2016

c හා c++ ප්‍රෝග්‍රැමිං - 10


ඉහත උදාහරණවලදී කළා මෙන් බොහෝමයක් ෆන්ක්ෂන් අප විසින්මයි සාදා ගන්නේ. එහෙත් සමහර ෆන්ක්ෂන් අප විසින් සාදන්නේ නැති බවද ඉහතදී දුටුවා. ඒවා වෙන අය විසින් සාදා තිබෙනවා. අපට තියෙන්නේ ඒවා අවශ්‍ය තැන්වල පාවිච්චි කිරීමටයි (printf, scanf යනු මෙවැනි ෆන්ක්ෂන්වලට උදාහරණ දෙකකි). අප විසින්ම සාදා ගන්නා ෆන්ක්ෂන් user-defined function (මෙහි තේරුම "අප/යූසර්/ප්‍රෝග්‍රැමර් විසින්ම සාදන ෆන්ක්ෂන්" යන්නයි) ලෙස හැඳින්වෙන අතර, වෙන අය සාදා අපට පාවිච්චි කිරීමට ලබා දී තිබෙන ෆන්ක්ෂන් library function ලෙස හැඳින්වෙනවා. මේවාට ලයිබ්රරි ෆන්ක්ෂන් යන නම ලැබී තිබෙන්නේ මෙලෙස ෆන්ක්ෂන් විශාල සංඛ්‍යාවක් සාමාන්‍යයෙන් ලබා දෙන බැවිනි (පොත් ගොඩක් තිබෙන තැනකට ලයිබ්රරි හෙවත් පුස්ථකාලයක් කියා කියන්නා සේ, ෆන්ක්ෂන් ගොඩක් තිබෙන තැනකුත් ලයිබ්රරි එකක් තමයි).

ඔබ විසින් අනර්ඝ විදියට සාදන ෆන්ක්ෂන් වෙනත් අයටත් නිතර නිතර අවශ්‍ය වේ යැයි සිතනවා නම්, ඔබටත් පුලුවන් ඒවා වෙන අයට ලබා දෙන්නට කටයුතු කරන්න. එවිට ඔබේ එම ෆන්ක්ෂන් එකත් ලයිබ්රිරි ෆන්ක්ෂන් එකක් වේවි. බොහෝ ප්‍රෝග්‍රැමර්ස්ලා ඇත්තටම බහුලව අවශ්‍ය වන වැදගත් වැඩකටයුතු කර ගැනීමට එලෙස ෆන්ක්ෂන් ලයිබ්රරි එකක් (එනම් ෆන්ක්ෂන් පුස්තකාලයක්) සාදා ගන්නවා. එවිට, ඔවුන් ප්‍රෝග්‍රෑම් සාදන විට, බොරුවට වරු ගණන් ප්‍රෝග්‍රෑම් ලිය ලිය ඉන්නේ නැතිව තමන්ගේ ලයිබ්රරි එකේ තිබෙන ෆන්ක්ෂන් යොදා ගෙන ඉක්මනින්ම ප්‍රෝග්‍රෑම් එක සාදන්නට හැකියාව ලැබී තිබෙනවා. ෆන්ක්ෂන් භාවිතය නිසා ඇති වූ තවත් ඉතාම වැදගත් වාසියක් තමයි එය. සමහරුන් නොමිලේ ලයිබ්රරි ෆන්ක්ෂන් (හෝ ෆන්ක්ෂන් ලයිබ්රරි) ලබා දෙන අතර, සමහරුන් මුදලට ලබා දේ.

ෆන්ක්ෂන් එකක් ඩිෆයින් කරන්නේ ප්‍රෝග්‍රෑම් එකේ කොතැනද? main() එකට පෙරද? පසුද? ඇත්තෙන්ම මෙය වැදගත් ප්‍රශ්නයක්. main() ට පෙරයි මාගේ උදාහරණවල නම් එය කර තිබෙන්නේ. ඔබටත් එලෙසම ඔබේ සෑම ෆන්ක්ෂන් එකක්ම main() ට පෙර ඩිෆයින් කළ හැකියි. එහෙත් ප්‍රායෝගික තලයේදී සාමාන්‍යයෙන් ෆන්ක්ෂන් ඩිෆයින් කර තිබෙන්නේ main() ට පසුවයි (එවිට ප්‍රෝග්‍රෑම් එකක් කියවීමට හා තේරුම් ගැනීමට පහසුවක් ඇති වේ). මා පහත දක්වා තිබෙන උදාහරණයේදී ෆන්ක්ෂන් එක ඩිෆයින් කර තිබෙන්නේ main() ට පසුවයි. එය වැඩ කරනවාද නැද්ද කියා බැලීමට ඔබත් එය කම්පයිල් කර බලන්න.

#include <stdio.h>

int main()
    {
    int result2;
    result2 = MultiplyNumbers(20, 10);
    printf("the result2 has %d\n",result2); /* displays the result2 */
    return 0;
    }

/* A simple function to multiply 2 numbers */
int MultiplyNumbers(int a, int b)
    {
    int result;
    result = a * b;
    return(result);
    }

සමහර අයට මෙය කම්පයිල් වේවි; සමහර අයට කම්පයිල් කරන්නට ඉඩ නොදී එරර් එකක් ලබා දේවි. කම්පයිල් වන අයට වුවත්, එය කම්පයිල් වන විට, යම් කිසි අවවාදයක් (warning) නම් ලබා දෙනවාමයි. කම්පයිල් වෙනවාද නැද්ද යන්න තීරණය වන්නේ ඔබ යොදා ගන්නා කම්පයිලරය අනුවයි. එහෙත් සම්මතයක් ලෙස නම්, කම්පයිල් නොවිය යුතුයි! (ඔබ දන්නවා ලෝකයේ සියලු දේම සිදු වන්නේ සම්මතය හෝ නීතියට අනුව නොවෙයිනෙ). මාගේ පරිගණකයේදිත් එය කම්පයිල් වූවා; එහෙත් පහත ආකාරයේ වෝර්නිං එකකුත් (අවවාදයක්) ලැබුණා.


සටහන
කම්පයිල් කිරීමේදී ඔබේ ප්‍රෝග්‍රෑම් එක හරියටම නිවැරදියි නම්, කිසිදු එරර් හෝ වෝර්නිං මැසේජ් නොලැබම එය සිදු වේවි. එහෙත් ප්‍රෝග්‍රෑම් එකේ බරපතල වැරදි ඇත්නම් ඔබ දන්නවා කම්පයිල් නොවී එම වැරැද්ද ගැන කෙටි සටහනක් (ඊට අප error message කියා කියනවා) ලැබේවි. තවත් අවස්ථාවලදී එරර් මැසේජ් නොදී වෝර්නිං මැසේජ් එකක් ලබා දේ. මෙහිදී ඇති විශේෂත්වය වන්නේ ප්‍රෝග්‍රෑම් එක කම්පයිල් වීමයි. එහෙත් සුලු දෝෂ තිබෙන බව වෝර්නිං එකේදී කියයි. බොහෝවිට මෙම සුලු දෝෂ ප්‍රෝග්‍රෑම් එකට හානියක් සිදු නොකරයි (එනිසා තමයි එම දෝෂ තිබියදීත් කෝඩ් එක කම්පයිල් වන්නේ). වෝර්නිං මැසේජ් එක කියවා එම දෝෂද ඉවත් කරන්නට කටයුතු කරන්නේ නම් එය ඉතා හොඳ ප්‍රෝග්‍රෑම් පුරුද්දකි.

ඒ අනුව දැන් ඔබට වැටහෙන්නට ඕන ෆන්ක්ෂන් එකක් main() ට පෙර ඩිෆයින් කර ඇති විට කිසිදු ගැටලුවක් නැතත්, main() ට පසුව ඩිෆයින් කරන විට යම් ගැටලුවක් ඇති බව. ඊට හේතුව සරලයි. නැවත ඉහත උදාහරණය බලන්න. සෝස් කෝඩ් එක ඔබ මුල ඉඳන් පේලියෙන් පේලියට කියවාගෙන යන්න (සාමාන්‍යයෙන් කම්පයිලරයද කියවන්නේ එලෙසයි). එසේ කියවගෙන යන අතරේදී ඔබට/කම්පයිලරයට හමුවෙනවා result2 = MultiplyNumbers(20, 10); යන ස්ටේට්මන්ට් එක. එහි තිබෙනවා MultiplyNumbers යනුවෙන් එකක්. එය කුමක්ද? ඔබ එය කුමක්දැයි දන්නේ නැහැනෙ. (ඔබ දැන් කියාවි මොකද දන්නෙ නැත්තේ ඉන් සිදු කරන්නේ සංඛ්‍යා දෙකක් ගුණ කර ගුණිතය රිටර්න් කරන එක කියා; ඔබ එලෙස කියන්නේ මීට පෙර උදාහරණවලදී අප ඒ ගැන බොහෝමයක් කතා කළ නිසාය; එහෙත් පළමු පාරට කියවන කෙනෙකුට නම්, ඉන් එතරම් දෙයක් හැඟවෙන්නේ නැත.) එම දේමයි කම්පයිලරයටත් සිදු වන්නේ. පසුවට එම ෆන්ක්ෂන් එකෙන් කරන්නේ කුමක්දැයි සටහන් වුවත්, ඔබ එය දැන්ගන්නට දැන් සිටින තැන පසු කර යා යුතුය. ප්‍රශ්නය තිබෙන්නේ ඔබ දැන් සිටින ස්ථානයේය. ඉතිං එම කමාන්ඩ් එක රන් නොකර පස්සෙ ඒක ගැන බලා ගන්නම් කියා යා නොහැකියි. එහෙත් ෆන්ක්ෂන් එක main() ට පෙර ඩිෆයින් කර තිබුණා නම්, එම ගැටලුව ඇති වෙන්නේ නැත මොකද ෆන්ක්ෂන් එක කෝල් කරන්නට පෙර ෆන්ක්ෂන් එක ගැන අප/කම්පයිලරය දන්නවා.

මීට පිළියම් දෙකක් තිබේ. එකක් නම් කම්පයිලරය සෝස්කෝඩ් එකක් කම්පයිල් කිරීමේදී කිහිප පාරක්ම සෝස්කෝඩ් එක කියවා පෙර විස්තර කළ විදියට නොදන්නා ෆන්ක්ෂන් නේම් එකක් දුටු විට, සෝස් කෝඩ් එකේ පසු කොටසේ එය තිබේදැයි සොයා බැලිය හැකියි. ඇත්තටම සමහර කම්පයිලර් සිදු කළේ එය තමයි. එසේ සිදු කළත්, එය සී කම්පයිලර් එක ක්‍රියා කරන සම්මත ක්‍රමය නොවන නිසා, වෝර්නිං එකක් ලබා දෙනවා (තවද සෑම කම්පයිලරයක්ම එය සිදු කරන්නේද නැත).

දෙවැනි පිළියම හැමතිස්සෙම ක්‍රියා කරන ඉතා හොඳ එකකි. මෙහිදීත් සියලුම ෆන්ක්ෂන් ඩිෆයින් කරන්නේ main() ට පසුවයි. එහෙත් එම ෆන්ක්ෂන්වල හෙඩර් කොටස පමණක් main() ට පෙර ලිවිය යුතුය (අගට සෙමිකෝලන් එකක්ද දැමිය යුතුයි). පහත උදාහරණයෙන් එය පැහැදිලි වේවි. පහත ප්‍රෝග්‍රෑම් එකත් කම්පයිල් කර බලන්න. කිසිදු වෝර්නිං එකක් හෝ එරර් එකක් නොලැබී සාර්ථකව කම්පයිල් වේවි.

#include <stdio.h>

int MultiplyNumbers(int a, int b); /* function prototype */

int main()
    {
    int result2;
    result2 = MultiplyNumbers(20, 10);
    printf("the result2 has %d\n",result2); /* displays the result2 */
    return 0;
    }

/* A simple function to multiply 2 numbers */
int MultiplyNumbers(int a, int b)
    {
    int result;
    result = a * b;
    return(result);
    }

ඉහත කෝඩිංවල තද අකුරින් පෙන්වා තිබෙන්නේ සිදු කළ වෙනසයි. එම කොටස බැලූබැල්මට ෆන්ක්ෂන් හෙඩර් එකට සමානයි නේද? ඔව්. එහෙත් දැන් එම කොටසට ෆන්ක්ෂන් හෙඩර් කියා කියන්නේ නැත. එය හඳුන්වන්නේ function prototype කියාය. ෆන්ක්ෂන් ප්‍රොටෝටයිප් එකේ රාජකාරිය තමයි, ප්‍රෝග්‍රෑම් එක ආරම්භයේදීම කම්පයිලරයට (හා ඔබට) මතක් කර දෙනවා, පහත ප්‍රෝග්‍රෑම් එක රන් වීමේදී මෙන්න මේ මේ ආකාරයේ ෆන්ක්ෂන් ඔබට හමු වේවි කියා. එවිට, කම්පයිලරය සූදානම් වෙනවා එම ෆන්ක්ෂන් මොනවාද කියා කල්තියාම සොයා බලන්නට. අප සාදන සෑම ෆන්ක්ෂන් එකකම (එනම් යූසර්-ඩිෆයින්ඩ් ෆන්ක්ෂන් සඳහා) මෙලෙස ප්‍රොටෝටයිප් ලිවිය යුතුයි.

දැන් ප්‍රශ්නයක් මතු වෙනවා එතකොට printf, scanf වැනි ලයිබ්රරි ෆන්ක්ෂන්වල ප්‍රොටෝටයිප් ලිව්වේ නැත්තේ මොකද කියා. ඇත්තෙන්ම ඒවා සඳහාද ප්‍රොටෝටයිප් ලිවිය යුතුයි. එසේනම් ඒවා ඉහත කිසිදු ප්‍රෝග්‍රෑම් එකක් නොතිබුණේ ඇයි? ඒවා නොතිබුණා නොවේ; ඒවා තිබුණා. එහෙත් එකවර ඔබට ඒවා පෙනෙ ලෙස නෙමේ තිබුණේ. එය සිදු කළේ ඒ සෑම ප්‍රෝග්‍රෑම් එකකම මුලින්ම #include <studio.h> යන කොටසින්. මේ ගැන දැන් විමසා බලමු.

#include යන "කමාන්ඩ්" එකෙන් සිදු කරන එකම රාජකාරිය ඊට පසුව ලියනු ලබන වචනයෙන් හඳුන්වන ෆයිල් එක කියවා එම ෆයිල් එකේ තිබෙන සියලුම අන්තර්ගතය හෙවත් අකුරු (කෝඩිං) include කමාන්ඩ් එක තිබෙන තැනට "කොපි පේස්ට්" කිරීම පමණයි. ඇත්තටම මෙය මා කමාන්ඩ් ලෙස හැඳින් වුවත්, එය කමාන්ඩ් එකක් නොවේ. ඊට directive හෝ preprocessor directive යැයි කියනවා (directive යන ඉංග්‍රිසි වචනයේ සාමාන්‍ය තේරුම “අණ කිරීම” යන්නයි). ඇත්තෙන්ම සී වල include හැරුණහම තවත් ඩිරෙක්ටිව් කිහිපයක්ම තිබෙනවා (ඒවා ගැන පසුව බලමු). සෑම ප්‍රෝග්‍රෑම් එකකටම නැතිවම බැරි ඩිරෙක්ටිව් එක තමයි include. ඩිරෙක්ටිව් එකක් හැමවිටම # සලකුණට (මෙම සලකුණ pound හෝ hash සලකුණ ලෙස හඳුන්වනවා) පසුවයි ලියන්නේ. ඩිරෙක්ටිව් එකක් කියා හඳුනාගන්නේ ඒ මඟිනි. කමාන්ඩ් නොවන නිසා, මේවාට පිටුපසින් සෙමිකෝලන් යොදන්නේ නැත.

මීට කමාන්ඩ් කියා නොකියන හේතුව මෙයයි. කමාන්ඩ් එකක් යනු ප්‍රෝග්‍රෑම් එකක් රන් වන විට, ක්‍රියාත්මක වන එකකි. එවිට, සෝස්කෝඩ් එකේ මෙන්ම බයිනරි කෝඩ් එකෙත් එම කමාන්ඩ් පවතිනවා (සෝස්කෝඩ් එකේදි ඉංග්‍රිසි වචනයක් හෝ යම් සංඛේතයක් ලෙසත්, බයිනරි කෝඩ් එකේදී 1 හා 0 ආශ්‍රයෙනුත් එම කමාන්ඩ් පවතිනවා). එහෙත් ඩිරෙක්ටිව් එකක් රන් වන්නේ නැත. ඊට හේතුව කිසිම ඩිරෙක්ටිව් එකක් බයිනරි කෝඩිං තුලට යන්නේ නැති වීමයි. ඇත්තටම සෝස් කෝඩ් එක කම්පයිල් වීමට පෙර, තවත් ක්‍රියාවලියක් සිදු වෙනවා (එම ක්‍රියාවලිය preprocessor ලෙස හැඳින්වෙනවා).

සටහන
මෙතෙක් මා පැවසුවේ සෝස්කෝඩ් ලියා එය කම්පයිල් කරන්න කියා පමණි. එය බැලූබැල්මට තනි ක්‍රියාවක් වගේ ඔබට පෙනුනත් ඇත්තටම එතැන ක්‍රියාවලි කිහිපයක් පිලිවෙලින් සිදු වේ. ඉන් එක් ක්‍රියාවලියක් තමයි preprocessor එක ක්‍රියාත්මක වීම. ඉන්පසු තමයි කම්පයිල් ක්‍රියාවලිය සිදු වන්නේ. මෙම කම්පයිල් ක්‍රියාවලියත් සමහරවිට තවත් උපක්‍රියාවලි කිහිපයකින් යුක්ත විය හැකියි. උදාහරණයක් ලෙස linking නම් උපක්‍රියාවලියක් කම්පයිල් ක්‍රියාවලිය තුල ඇත. එහෙත් මේ සියල්ල සිදු වන්නේ ඔබට නොදැනී ස්වයංක්‍රියවයි. ඒ නිසා අමුතුවෙන් බය වන්නට දෙයක් එහි නැත.

එම ප්‍රීප්‍රොසෙසර් ක්‍රියාවලිය තුලදී තමයි ඩිරෙක්ටිව්වල බලපෑම තිබෙන්නේ. ඉතිං, ප්‍රීප්‍රොසෙසර් ක්‍රියාවලියේදී include ඩිරෙක්ටිව් එකේ රාජකාරිය වන යම් ෆයිල් එකක අන්තර්ගතය සෝස්කෝඩ් එකේ කොපි කිරීම සිදු වේ. එවිට, කම්පයිලරය ක්‍රියාත්මක වන අවස්ථාව වන විට include ඩිරෙක්ටිව් එකක් දක්නට ලැබෙන්නේ නැත; ඒ වෙනුවට තිබෙන්නේ යම් ෆයිල් එකක තිබූ දේවල් කොපි වී තිබීමයි (මෙලෙස කොපි වන්නේද සී කෝඩිං බව අමුතුවෙන් කිව යුතු නැහැනෙ). උදාහරණයක් ඇසුරින්ම මෙය බලමු. පහත කෝඩිං ලියා එය sample.h යන නමින් සේව් කරගන්න.

/* sample.h file for demo */

/* A simple function to multiply 2 numbers */
int MultiplyNumbers(int a, int b)
    {
    int result;
    result = a * b;
    return(result);
    }

දැන් පහත කෝඩිං එකත් sample.c ලෙස (හෝ තමන් කැමති වෙනත් නමකින්) ඉහත sample.h යන ෆයිල් එක සේව් කළ ෆෝල්ඩර් එකේම සේව් කර, කම්පයිල් කර රන් කර බලන්න. සාර්ථකව රන් වේවි.

#include <stdio.h>

#include “sample.h”

int main()
    {
    int result2;
    result2 = MultiplyNumbers(20, 10);
    printf("the result2 has %d\n",result2); /* displays the result2 */
    return 0;
    }

බලන්න දැන් අපි MultiplyNumbers යන ෆන්ක්ෂන් එක යොදා ගෙන තිබුණත්, එම ෆන්ක්ෂන් එකේ ඩෙෆිනිෂන් එක (හා ප්‍රොටෝටයිප් එක) දක්නට නැහැ. ඔබට එකවරම පෙනෙන්නේ ඉහත කුඩා කොඩිං කොටස පමණි. එහෙත් කම්පයිලරයට ඊට වඩා දිගු කෝඩිං එකක් තමයි පෙනෙන්නේ. ඊට හේතුව කම්පයිල් වන්නට මොහොතකට පෙර include යන ඩිරෙක්ටිව්ස් ක්‍රියාත්මක වී වෙනත් අමතර කෝඩිං ප්‍රමාණයක් මෙම සෝස්කෝඩ් එකට එකතු කිරීමයි. ඒ අනුව ඇත්තටම කම්පයිල් වන මොහොතේදී කම්යපයිලරයට පේන්නේ පේලි 1000කට වඩා ඇති විශාල සෝස් කෝඩ් එකකි. කම්පයිලරයට ඇත්තටම පෙනෙන එම පේලි 1000කට අධික සෝස්කෝඩ් එක මා මෙහි පෙන්වන්නට යන්නේ නැත (එය නිකරුණේ පිටු නාස්තියක් නිසා). ඉහත ප්‍රෝග්‍රෑම් එකේ පේලි ඇත්තේ 11ක් පමණය. #include “sample.h” යන්න ක්‍රියාත්මක වීම නිසා තවත් පේලි 9ක් පමණ ඊට එකතු විය (sample.h ෆයිල් එකේ තිබුණේ පේලි 9ක් නිසා). ඉතිරි පේලි නමසිය ගණනම #include <stdio.h> යන්න ක්‍රියාත්මක වීම නිසාය (ඒ කියන්නේ stdio.h යන ෆයිල් එකේ පේලි නමසිය ගණනක් තිබේ).

සටහන
ඔබට ආසාවක් ඇත්නම් stdio.h ෆයිල් එකේ තිබෙන්නේ මොනවාද කියා දැන ගන්නට, ලිනක්ස් මෙහෙයුම් පද්ධතියක නම්, මෙම ෆයිල් එක /usr/include/ යන පාත් එකේදී දැක ගත හැකියි. වින්ඩෝස් මෙහෙයුම් පද්ධතියක නම්, ඔබ භාවිතා කරන කම්පයිලරය හෝ IDE එක අනුව එය පිහිටන පාත් එක වෙනස් වේ (එනිසා search කර එය සොයා ගන්න).

ෆන්ක්ෂන් එකක් තවත් ෆන්ක්ෂන් එකක් තුල සිට කෝල් කළ හැකියි. එවිට කෝල් කරන ෆන්ක්ෂන් එක calling function හෝ caller යනුවෙන් හැඳින්වෙන අතර, කෝල් කරනු ලබන ෆන්ක්ෂන් එක called function හෝ callee ලෙස හැඳින්වේ. පහත උදාහරණය බලන්න.

/* A demo program to show how caller and callee works */

#include <stdio.h>

/* function prototypes */

void CalleeFunc1();
void CalleeFunc2(int num1);
void CallerFunction();

int main()
    {
    printf("I am now in main function\n");
    CallerFunction(); /* Calling the CallerFunction() */

    return 0;
    }

/* function definitions */

void CalleeFunc1()
    {
    printf("I am in callee function 1 now\n");
    CalleeFunc2(29); /* Calling CalleeFunc2 from within CalleFunc1 */
    }

void CalleeFunc2(int num1)
    {
    printf("I am in callee function 2 now with %d\n",num1);
    }

void CallerFunction()
    {
    printf("I am in the caller function\n");
    CalleeFunc1(); /* Calling CalleeFunc1 from within CallerFunction */
    printf(“End of function calls\n”);
    }

ඉහත උදාහරණයේ ෆන්ක්ෂන් 3ක් ඇත. main() තුල සිට පළමුව CallerFunction නම් ෆන්ක්ෂන් එක කෝල් කරයි. එම ෆන්ක්ෂන් එකේ ඇත්තේ ස්ටේටම්න්ට් 2කි. පළමුව අැති printf() ෆන්ක්ෂන් එකෙන් I am in the caller function යන්න දර්ශනය කරයි. දෙවැනි ස්ටේට්මන්ට් එකෙන් කරන්නේ CalleeFunc1 නම් ෆන්ක්ෂන් එක කෝල් කිරීමයි. අප දැනටමත් සිටින්නේ CallerFunction නම් ෆන්ක්ෂන් එක තුලයි. එහි සිට (එනම් එම ෆන්ක්ෂන් බොඩි එකේ සිට) CalleeFunc1 නම් තවත් ෆන්ක්ෂන් එකක් කෝල් කරනවා. මෙහිදී CallerFunction යන්න calling function ලෙසත්, CalleeFunc1 යන්න called function ලෙසත් ක්‍රියා කරනවා නේද? CalleeFunc1 ෆන්ක්ෂන් එක දැන් රන් වන්නට පටන් ගන්නවා. එහෙත් තවමත් CallerFunction එක අවසන් වී නැත. එය අවසන් වන්නේ කෝල් කරපු CalleeFunc1 රන් වී අවසන් වූ පසුවයි.

දැන් CalleeFunc1 තුළද CalleeFunc2 යන ෆන්ක්ෂන් එක කෝල් කරනවා. එවිට, දැන් CalleeFunc2 රන් වන්නට පටන් ගන්නවා (මෙම අවස්ථාවේදී CalleeFunc2 යන්න called function එක වන අතර, CalleeFunc1 යන්න calling function වේ). CalleeFunc2 තුළ තවත් ෆන්ක්ෂන් කෝල් කරන්නේ නැත. ඉතිං එය යම් මැසේජ් එකක් පමණක් දර්ශනය කර අවසන් වෙනවා. ඉන්පසු එය කෝල් කරපු CalleeFunc1 නම් ෆන්ක්ෂන් එකට ආපසු ක්‍රියාකාරිත්වය ලැබෙනවා. CalleeFunc1 තුල ෆන්ක්ෂන් කෝල් එකට පසු තවත් රන් වන්නට කෝඩිං නැති නිසා, CalleeFunc1 එකත් රන් කර අවසන් වෙනවා. එවිට, CalleeFunc1 එක කෝල් කරපු CallerFunction එකට ආපසු ක්‍රියාකාරිත්වය ලැබෙනවා. එහි ෆන්ක්ෂන් කෝල් එකට පසුව තවත් printf() කමාන්ඩ් එකක් රන් වෙන්නට තිබෙන නිසා, එයත් රන් වී එම ෆන්ක්ෂන් එකත් අවසන් වෙනවා. ඉන්පසු CallerFunction එක කෝල් කරපු main() එකට ක්‍රියාකාරිත්වය ලැබෙනවා. එහිත් අමුතුවෙන් තවත් රන් වන්නට කමාන්ඩ් නැති නිසා සම්පූර්ණ ප්‍රෝග්‍රෑම් එකම අවසාන වනවා.

ෆන්ක්ෂන් එකක () තුළ පැරාමීටර්ස් ලිවිය හැකි බව ඔබ දන්නවා. යම් ෆන්ක්ෂන් එකක පැරාමීටර්ස් තිබේ නම්, එම ෆන්ක්ෂන් එක කෝල් කරන මොහොතේදී ඊට සුදුසු දත්තයන් ලබා දිය යුතු බවද ඔබ දන්නවා. එවිට එම දත්තයන්ටද parameter කියා කිව හැකියි. උදාහරණයක් ලෙස, int func1(long a); යන ෆන්ක්ෂන් හෙඩර් එකේ long a ලෙස තිබෙන්නේ එම func1 යන ෆන්ක්ෂන් එකේ පැරාමීටරයනෙ. ඉතිං එම ෆන්ක්ෂන් එක පසුව කෝල් කරන විට, func1(15211); වැනි ආකාරයකට කළ හැකියිනෙ. long දත්ත වර්ගයට ගැලපෙන දත්තයක්නෙ 15211 කියන්නේ. මෙම 15211 යන්නටත් parameter කියා කියන බවයි මා ඉහතදී පවසුවේ.

එහෙත් මේ දෙකටම පැරාමීටර් කියා කිව්වත් ඒ දෙකේ වෙනස පෙන්වීමට අවශ්‍ය වෙනවා. එනිසා 15211 ලෙස ඇති (එනම් "නියම දත්තය" ලෙස ඇති) විට, ඊට actual parameter හෙවත් argument කියා කියනවා. ඒ කියන්නේ ෆන්ක්ෂන් එක කෝල් කරන විට ලබා දෙන දත්තය ඇක්චුවල් පැරාමීටර් හෙවත් ආර්ග්‍යුමන්ට් කියා කියනවා. ෆන්ක්ෂන් එක ඩිෆයින් කරන විට තිබෙන පැරාමීටරය formal parameter හෝ නිකංම පැරාමීටරය ලෙස හඳුන්වනවා.

අප දැන් main() ගැන විමසා බලමු. ඇත්තෙන්ම එයද ෆන්ක්ෂන් එකකි. එහි විශේෂත්ව කිහිපයක් තිබේ. එකක් නම්, මෙම ෆන්ක්ෂන් එකේ ෆන්ක්ෂන් නේම් එක හැමවිටම main ලෙස ලිවිය යුතුමයි. එහි රිටර්න් ටයිප් එක int වේ. එහෙත් අවශ්‍ය නම් එය void ලෙසත් ලිවිය හැකියි (එවිට වෝර්නිං එකකුත් ලැබේවි). අපට එරර් හෝ වෝර්නිං අවශ්‍ය නැති නිසා void නොදා int ලෙසම ලියන්නට පුරුදු වෙමු. සාමාන්‍යයෙන් අපට පුලුවන් පැරාමීටර්ස් නොලියා නිකංම () ලෙස තබන්න. මෙම විස්තරය අනුව ඔබට දැන් තේරෙනවා මේන් ෆන්ක්ෂන් එක පහත ආකාරයට තැබිය යුතුයි කියා.

int main()
{ }

මේන් ෆන්ක්ෂන් එක යනු සී ප්‍රෝග්‍රෑම් එකක අනිවාර්යෙන්ම තිබිය යුතු එකකි. එමනිසාමයි ඊට main යනුවෙන් නම් තබා තිබෙන්නෙත් (main යනු "ප්‍රධාන" යන තේරුම දෙන ඉංග්‍රීසි වචනයකි). මීට පෙරත් සඳහන් කළ ලෙසම, සෑම සී ප්‍රෝග්‍රෑම් එකක්ම රන් වන්නට පටන් ගන්නේ main ෆන්ක්ෂන් එකෙන්ය.

සාමාන්‍යයෙන් මේන් ෆන්ක්ෂන් එක අවසාන කරන්නේ return(0); හෝ return 0; යන කමාන්ඩ් එකෙනි. මේන් ෆන්ක්ෂන් එකේ හෙඩර් එකේ int රිටර්න් ටයිප් එක ලියන බව ඉහතදී පැවසුවා. ඉතිං මේන් ෆන්ක්ෂන් එක අවසානයේ int දත්ත වර්ගය ගැලපෙන අගයක් රිටර්න් කළ යුතුයි. ඔබට ඕන ඕන අගයක් මෙහි රිටර්න් නොකළ යුතුය. ප්‍රෝග්‍රෑම් එක සාර්ථකව රන් වී අවසන් වූ බව මෙහෙයුම් පද්ධතියට දන්වන්නේ මේන් ෆන්ක්ෂන් එක අවසන් වන විට 0 යන අගය රිටර්න් කිරීමෙනි. එහෙත් ඔබ මේන් එකේ රිටර්න් ටයිප් එක ලෙස void යෙදුවා නම්, මේන් එකේ අවසානයේ මෙවැනි return ස්ටේට්මන්ට් එකක් ලියන්නට බැහැ.

සටහන
ඔබේ ප්‍රෝග්‍රෑම් එක සාර්ථකව අවසන් වූවාද නැද්ද කියා ප්‍රෝග්‍රැමර් වශයෙන් ඔබ පමණක් නොව පරිගනකය මත සියලුම ප්‍රෝග්‍රෑම් රන් කරන මෙහෙයුම් පද්ධතියත් එය දැන ගත යුතුයි. ඉතිං මේන් ෆන්ක්ෂන් එකෙන් 0 අගය රිටර්න් වූ විට ඉන් සංඥා කරනවා මෙම ප්‍රෝග්‍රෑම් එක සාර්ථකව වැඩ නිම කළා කියා. සාමාන්‍යයෙන් මෙම return(0); ස්ටෙට්මන්ට් එක තිබෙන්නේ මේන් ෆන්ක්ෂන් එකේ අවසානයේය. ප්‍රෝග්‍රෑම් එක මෙම අවසාන ස්ටේට්මන්ට් එක දක්වා රන් වූවා යැයි කියන්නේම එය සාර්ථකව රන් වූවා කියන එකනෙ. මීට පෙර යම් තැනකදී ප්‍රශ්න මතු වූයේ නම්, මෙම අවසන් ස්ටේට්මන්ට් එක දක්වා ඊට රන් වීටම ඉඩ ලැබෙන්නේ නැහැනෙ. එනිසා ඇත්තටම මෙය හොඳ ක්‍රමයක් නේද ප්‍රෝග්‍රෑම් එක සාර්ථකව රන් වූවා කියා මෙහෙයුම් පද්ධතියට දන්වන?

දැන් ඔබට සී ප්‍රෝග්‍රෑම් එකක් සෑදීමට අවශ්‍ය මූලික දැනුම සියල්ල ලබා දී ඇත. සාමාන්‍යයෙන් සී ප්‍රෝග්‍රෑම් එකක් පහත පොදු ආකාරයෙන් (ෆෝමැට් එක) තමයි පවතින්නේ.

/* මෙම කොටසෙහි #include වැනි ඩිරෙක්ටිව්ස් ලියන්න */
#include <stdio.h>
#include < ……….>
………

/* මෙම කොටසෙහි අවශ්‍ය නම් ෆන්ක්ෂන් ප්‍රොටෝටයිප් ලියන්න */
int func1();
void func2();
………

/* මෙම කොටසෙහි අවශ්‍ය නම් වේරියබල් ආදිය ඩිෆයින් කරන්න */
long var1;
char var2;
………

/* මෙතැන මේන් ෆන්ක්ෂන් එක ඇත */
int main()
{
/* මේන් ෆන්ක්ෂන් එකේ අන්තර්ගතය */
.....…
return 0;
}

/* මෙම කොටසෙහි අවශ්‍ය නම් ෆන්ක්ෂන් ඩිෆයින් කරන්න */
int func1()
{
…..
}

void func2()
{
…..
}

/* ප්‍රෝග්‍රෑම් එකේ අවසානය */





c c++ programming (සී ප්‍රෝග්‍රැමිං)

2 comments:

  1. මම මෙ දවස් වල arduino ගැන ඉගෙන ගන්නවා..මෙ පාඩමි ටිකෙන් ගොඩක් ගැටඵ විසදුනා... පැහැදිලි කිරිමි සුපිරි....

    ReplyDelete
    Replies
    1. ඉදිරියටත් කිවන්න... සති දෙකකින් විතර අදයි මං ඉන්ටර්නෙට් එකට කනෙක්ට් වුණේ. ඒක නිසා පාඩම ටික දවසකට නැවතුණා.

      Delete