មេរៀនទី៦: អនុគមន៍ និង ម៉ាក្រូ

មេរៀនទី៦: អនុគមន៍ និង ម៉ាក្រូ Function & Macro

I. សញ្ញាណទូទៅនៃ   SubProgram

ក្នុងការសរសេរកមμវិធី យើងតែងជួបប្រទះផ្នែកមួយ ចំនួន របស់ កមμវិធីត្រូវបានសរសេរ ម្ដងហើយម្ដងទៀតជាច្រើនលើក ច្រើន សារនៅតាមកន្លែងខុសៗគ្នា។  ដើម្បីជៀសវាងការ សរសេរ ច្រើន ដងនូវ កំណាត់កមμវិធីដដែលនេះ យើងអាចយកកំណាត់កមμវិធីទាំង នេះទៅបង្កើត ជាកមμវិធីរង (Subprogram) ហើយយកឈេμាះ របស់កមμវិធីរងនោះទៅជំនួសនៅតាម កន្លែងដែលត្រូវប្រើកំណាត់ កមμវិធីនេះ។ មានន័យថា ពេលណាចាំបាច់ត្រូវប្រើកំណាត់កមμវិធី មុននេះយើងគ្រាន់តែហៅឈេμាះរបស់កមμវិធីរងសមមូលនឹងវាមក ប្រើជាការស្រេច ដោយ មិនចាំបាច់សរសេរកំណាត់កមμវិធីទាំងនោះ ឡើងវិញជាច្រើនលើកច្រើនសាឡើយ។ ឧទាហរណ៍ ថាពេលធ្វើ លំហាត់ គណនា cos ឬ sin នោះយើងត្រូវគណនាជាច្រើនលើកច្រើន សានូវ sin របស់មុំណាមួយ ដូច្នេះយើងត្រូវបង្កើតកមμវិធីរងមួយ មាន ឈេμាះថា sin និងប៉ារ៉ាមែត្រ សមមូលរបស់វាគឺ x (ដែល x ទីនេះគឺ ជាមុំ ត្រូវគណនា)។ បណ្ដាកមμវិធីរងទាំងអស់នេះត្រូវ បានគេបង្កើត ឡើង រួចជា ស្រេច និងសរសេរប្រកាសវានៅក្នុង library file របស់ ភាសា សរសេរកមμវិធីមួយចំនួនដូចជា C, Pascal, Basic។ល។ ដូចនេះយើងអាចហៅកមμវិធីរង ទាំងនេះបានថាជាអនុគមន៍ដែល មាន ស្រាប់  ឬ Standard Subprogram ។ ក្នុង Turbo C បណ្ដា  Subprogram ទាំងនេះត្រូវបានបែងចែកទៅជាក្រុម ហើយទុកនៅក្នុង file ផ្សេងៗពីគ្នាដូចជា stdio.h , conio.h , math.h ជាដើម។

ហេតុផលមួយទៀតដែលត្រូវបង្កើតកមμវិធីរងគឺ នៅពេលសរសេរ កមμវិធី ធំមួយនោះ ភាពសμុគ្រសμាញជាច្រើនបានកើតឡើង ហើយពេលនោះកមμវិធីអាចមានប្រវែងវែងអន្លាយ ដែលបណ្ដាល អោយមានការពិបាកយ៉ាងខ្លាំងក្នុងការស្វែងរកកំហុស និងកែសំរួល។ ដូច្នេះយើងអាចផ្ដាច់បញ្ហាសμុគសμាញទាំងនោះទៅជាចំណែកតូចៗ គឺបង្កើតទៅជាកមμវិធីរង ឬជា បណ្ដុំ  (Block) ឬជាម៉ូឌុល ដើម្បីងាយ ស្រួលក្នុងការត្រួតពិនិត្យ និងស្វែងរកកំហុស តាមបំណែកនីមួយៗ របស់កមμវិធីរង បន្ទាប់មកទើបប្រមូលកមμវិធី រងទាំងនោះ មកផ្គុំ គ្នាដើម្បី បង្កើតជាកមμវិធីធំខាងលើវិញ។ កមμវិធីរង ត្រូវ បាន គេប្រើប្រាស់យ៉ាងទូលំទូលាយ ដូច្នេះចំណេះដឹងអំពីការប្រើ និង បង្កើតកមμវិធីរង គឺជាភាពចាំបាច់បំផុតសំរាប់អ្នក ក្នុងការសរសេរ កមμវិធី។ ក្នុងបណ្ដាភាសា សរសេរកមμវិធីមួយចំនួនដូចជា Basic ឬ Pascal ជាដើម  មានការបែងចែកកមμវិធីរង ជាពីប្រភេទគឺ Function និង Procedure តែក្នុង C/C++ វិញគឺមានតែ  Function មួយគត់។ II. អនុគមន៍       (Function ) ក្នុងភាសាសរសេរកមμវិធីកុំព្យូទ័រ អនុគមន៍គឺជាទំរង់បែបបទនៃការងារណាមួយ ដែលត្រូវបានកំណត់ ឈេμាះ នឹងត្រូវបានរក្សាទុកក្នុង Memory ដើម្បីឆ្លើយតបអោយអ្នក ប្រេនីវូ តៃំ លដែលមានប្រភេទណាមយួ   ។ ឧទាហរណ៍ដូចជា អនុគមន៍ NPV របស់ MS-Exel វានងឹ ផ្ដល់អោយអ្នកនូវតំលៃបច្ចុប្បន្ន (Present Value) គឺប៉ុនμាន?  ក្រោយពេលដែលអក្ន បាន បញ្ចូល ទិន្នន័យអោយវាមួយចំនួនដូចជា អំឡុងពេល  (Period)

អត្រាការ ប្រាក់  (Rate) និង តំលៃអនាគត (Future Value)។អនុគមន៍ត្រូវបានគេប្រេជីាមួយបណា្ដ កន្សោមផ្សេងៗបាន តែពុំអាច ចាត់ទុកវាថាជា Statement បានទេ។ អនុគមន៍យក ទិន្នន័យ ចូលតាមរយៈប៉ារ៉ាមែត្រ នឹងបោះតំលៃចេញមកខាងក្រៅវិញ តាមរយៈឈេμាះរបស់វា។ ក្នុង C យើងអាចប្រើអនុគមន៍ តាម បែបផែនផ្សេងៗគ្នា ៖

•     តៃំ លរបសអ់នុគមន៍ យើងអាចនឹងពុំយកវាប្រើក៏បាន ជាកែ់ ស្ដងដចូជាអនគុមន៍ printf និង scanfដែលអនុគមន៍ទាំងនោះ សុទ្ធតែផ្ដល់ តំលៃមកវិញមានប្រភេទជាចំនួនគត់។

•   អនុគមន៍ខ្លះអាចគμានតំលៃណាមួយត្រូវបានភ្ជាប់អោយ ឈេμាះរបស់វា (អនុគមន៍ ប្រភេទ void)។

•     ឈេμាះអនុគមន៍  អាចផ្ដល់តំលៃជាអាសយដ្ឋាន  Memory ដែលវាបានកំពុង  តែចង្អុលទៅរក(អនុគមន៍ប្រភេទ  Array ឬ Pointer)។

•     អនុគមន៍ អាចផ្លាស់ប្ដូរ ឬធ្វើអោយប្រែប្រួលតំលៃដើមរបស់ អាគុយម៉ង់។ ទោះបីជាហៅថាអនុគមន៍មែន ប៉ុន្ដែ C មិនបានកំណត់ លក្ខខណ្ឌនៃរបៀបប្រើប្រាស់ ទេ។ ក្រៅពីនេះទៀត C នៅផ្ដល់ លទ្ធភាព អោយយើងអាច Compile ម៉ូឌុលនីមួយៗដាច់ ដោយឡែក ពីគ្នាបាន ដែលបញ្ហានេះមានសារៈសំខាន់បំផុត នៅពេលដែល ចំណោទ ធំមួយ ត្រូវបានបំបែកទៅជាម៉ូឌុលតូចៗ និងសរសេរ ដោយឯករាកជ្យ។

ឧទាហរណ៏     ៖ គណនាអនុគមន៍គណិតវិទ្យាខាងក្រោម ៖

y = f(x) = f_ex(x) = x2 + bx + c

ដែលក្នុងនោះ x ជាចំនួនពិត ចំណែកឯ b និង c ជាចំនួនគត់ និងមាន ប្រើ f_ex

ជាឈេμាះរបស់អនុគមន៍។

/*—– កមμវិធី Prog5_1.C —–*/

#include <stdio.h>

#include <conio.h>

void main( )

{

float f_ex(float , int , int); /*ប្រកាសទំរង់អនុគមន៍មុនពេលប្រើវា */

float x = 1.5;

float y , z ;

int n = 3 , p = 5 , q = 10;

/*ហៅអនុគមន៍ f_ex ដើម្បីគណនា រួចហើយភ្ជាប់លទ្ធផលអោយអថេរ y  */

y = f_ex(x, n, p);

clrscr( );

printf(“Value of y = %f \n”, y); /* បង្ហាញតំលៃរបស់ y លើអេក្រង់  */

/*ហៅអនុគមន៍ f_ex ដើម្បីគណនា រួចហើយភ្ជាប់លទ្ធផលអោយអថេរ z  */

z = f_ex(x+0.5 , q , n – 1);

printf(“Value of z = %f \n”, z); /* បង្ហាញតំលៃរបស់ z លើអេក្រង់  */

getch();

}

/* ប្រកាសអនុគមន៍ – Declaring Function */

float f_ex(float x , int b , int c )

{

float value ; /* ប្រកាសអថេរដំបន់ */

2

/* គណនាអនុគមន៍ x +bx+c រួចយកលទ្ធផលភ្ជាប់អោយអថេរ value */value = x*x + b*x + c;

/*បោះតំលៃដែលកំពុងតែផ្ទុកក្នុងអថេរ value អោយទៅឈេμាះអនុគមន៍ */

return value ;

}

លទ្ធផលលើអេក្រង់គឺ ៖

Value of y = 11.750000

Value of z  = 26.000000

   វិភាគលើកមμវិធី  Prog5_1.C

អនុគមន៍ f_ex មានបីប៉ារ៉ាមែត្រសំរាប់យកទិន្នន័យចូល ទៅក្នុង តួអនុគមន៍។ មុនពេលហៅអនុគមន៍ប្រើ ជាដំបូងត្រូវសរសេរប្រកាស ទំរង់អនុគមន៍ (Prototype) នៅ ខាងដើមនៃកមμវិធីសិន (អាចក្នុង តួ អនុគមន៍ main ឬក៏អាចប្រកាសពីមុខ main ក៏បាន ដែរ) ដែលការ ប្រកាស នេះរួមមាន ឈេμាះរបស់អនុគមន៍ជាមួយប្រភេទទិន្នន័យ និងបណ្ដា

ប៉ារ៉ាមែត្ររបស់អនុគមន៍ (សំរាប់កមμវិធី Prog5_1.C នេះ ការប្រកាស ទំរង់អនុគមន៍ គឺនៅបន្ទាត់ float

f_ex(float , int , int); /*ប្រកាសទំរង់អនុគមន៍មុនពេលប្រើវា */ )។ ចំណែកឯការងាររបស់អនុគមន៍វិញយើងមិនទាន់ដឹងនៅឡើយទេ នៅខាងចុងនៃកមμវិធី

ទើបមានការប្រកាសអនគុមនព៍តិ  ប្រាកដ។ នៅក្នុងតួខ្លួនរបសអ់
នុគមន៍ main យើងបានហៅ អនុគមន៍ f_ex ចំនួនពីរដងជាមួយ Argument ផ្សេងៗគ្នា  ៖

*        ការហៅលើកទី 1 :

y = f_ex(x, n, p);

ក្នុងការហៅមួយនេះ Argument មានបីគឺ  x, n, p ដែល Argument ទាំងបីនេះ ត្រូវចំលងតំលៃអោយទៅប៉ារ៉ាម៉ែត្ររបស់ អនុគមន៍ តាមលំដាប់គឺ ៖
Argument x ចំលងតំលៃអោយទៅប៉ារ៉ាមែត្រ x របស់អនុគមន៍
Argument n ចំលងតំលៃអោយទៅប៉ារ៉ាមែត្រ b របស់អនុគមន៍
Argument p ចំលងតំលៃអោយទៅប៉ារ៉ាមែត្រ c របស់អនុគមន៍

*        ការហៅលើកទី 2 :

y = f_ex(x+0.5 , q , n-1);

ពេលនេះ Argument មានបីគឺ  x+0.5 , q , n-1 ដែល Argument ទាំងបីនេះ ត្រូវចំលងតំលៃអោយទៅប៉ារ៉ាម៉ែត្រ របស់អនុគមន៍ តាម លំដាប់គឺ ៖
Argument x+0.5 ចំលងតំលៃអោយទៅប៉ារ៉ាមែត្រ x របស់អនុគមន៍
Argument q ចំលងតំលៃអោយទៅប៉ារ៉ាមែត្រ b របស់អនុគមន៍
Argument n-1 ចំលងតំលៃអោយទៅប៉ារ៉ាមែត្រ c របស់អនុគមន៍
សរុបមកលំនាំនៃការហៅអនុគមន៍ f_ex មកប្រើក្នុងអនុគមន៍ main ត្រូវបានបង្ហាញ

បន្ថែមដោយរូបខាងក្រោម ៖
C C++C C++ចំណាំ   ៖     ចុងបន្ទាត់គμានសញ្ញាចុចក្បៀស (;) ទេ (គឺដូចគ្នាជា មួយការប្រកាស main ដែរ)

និងបណ្ដាប៉ារ៉ាមែត្ររបស់អនុគមន៍ត្រូវចែកដាច់ពីគ្នាដោយសញ្ញាក្បៀស (,) ។ កមμវិធីដែលអ្នកបានសរសេរតាំងពីមុនរហូតមកដល់ពេលនេះ សុទ្ធតែមានអនុគមន៍មួយជានិច្ចនោះគឺ main ដែលគμានប៉ារ៉ាមែត្រ និងក៏គμានសញ្ញាចុចក្បៀសនៅខាងចុងបន្ទាត់ដែរ។

ក្នុងតួខ្លួនអនុគមន៍ f_ex យើងឃើញថា អថេរដែលគេបានប្រកាស សំរាប់ ផ្ទុក លទ្ធផលអនុគមន៍ (អថេរ value) ត្រូវបានគេហៅថាជា អថេរ ដំបន់ (Local Variable)

ព្រោះអថេរនេះអាចប្រើបានតែនៅក្នុងខ្លួនរបស់អនុគមន៍ f_ex ប៉ុណ្ណោះ។ អថេរ value នោះត្រូវបានគេប្រើសំរាប់ផ្ទុក លទ្ធផល គណនារបស់កន្សោម  x*x + b*x +c ជាបណ្ដោះ អាសន្ន ដើម្បី ភ្ជាប់ លទ្ធផលនោះអោយទៅឈោμ ះរបស់អនុគមន៍តាមរយៈពាក្យគន្លឹះ return។ តំលៃរបស់អនុគមន៍មានអត្ថន័យដូចខាងក្រោម ៖

ឈេμាះអនុគមន៍ = តំលៃ

ឬមានន័យថា ៖

f_ex = តំលៃ = value

III. អនុគមន៍ក្នុងភាសា  C

+ parameter និង Argument

បណ្ដា parameter ប្រើនៅពេល Declaration Function ហៅថា parameter ។ បណ្ដា  parameter  ដែលផ្ដល់អោយ  Function  (ក្នុង  main   program)  នៅពេលយើងហៅ Function ហៅថា Argument ។ parameter ពិតអាចជាកន្សោមមួយក៏បាន, តែ parameter រូបភាពមិនអាចជាកន្សោមបានទេ ។

+ return Statement :

–  return : អាចផ្ដល់តំលៃនៃកន្សោមមួយទៅអោយឈេμាះ Function បាន ដូច្នេះ Function

ខាងលើអាចសរសេរជា ៖

/ * Declaration */

float f_Exam (float x, int b, int c)

{

return ( x * x + b * x + c );

}

បានន័យថាយើងមិនចាំបាច់ Declaration local Variable ទេ ។

–   return អាចសរសេរច្រើនដងក្នុង Function ។

Example :

double tt (double a, double b )

{ double s ;

s = a + b

if ( s> 0 ) return (s) ;

else return (-s);

}

–     បើប្រភេទរបស់កន្សោមក្នុង return ផ្ទុយពីប្រភេទរបស់ឈេμាះ Function នោះ Turbo C និង ប្ដូរ ប្រភេទសមមូលអោយវិញ ។

–     យើងអាចមិនប្រើតំលៃលទ្ឋផលរបស់ Function បាន ។ Example printf ( ), scanf ( ) ។

–     ករណី  Function   គμានតំលៃតបតវិញ     (តំលៃផ្ដល់អោយ ឈេμាះ     Function)   Function

មួយដែលគμានតំលៃ តបតវិញនោះយើងប្រើ Keyword void ដើម្បី Declaration វា ។

Example :

void Function_Name (int n);

–     Function ប្រភេទ Void នេះគμាន Statement return ទេ ។

–     ករណី Function គμាន parameter :

មាន Function មួយចំនួនគμាន  parameter ទេ ។ ដូច្នេះ Declaration Function នោះយើងប្រើ

Keyword void :

Ex: float Exam_para (void );

នៅមានករណីផ្សេងទៀតដូចខាងក្រោម ៖

void Exam_display (void )

បានន័យថា គμានតំលៃតបត, និងគμាន parameter ទេ ។

ចូរពិនិត្យបណ្ដា Example ខាងក្រោម ៖

# include <stdio.h>

# include <conio.h>

main ( )

{          /* prototype */

void          display_square ( int, int );

void          ONError (void );         /* have got a Error */

int             Start1 = 56, End1 = 10;

display_square (start1, End1);

if (…) ONError ( ); /* Error */

}

void display_square (int d, int f )

{ int i;

for ( i = d, i <= f; i ++ )

printf (“%d square root is %d \n”, i, i * i );

}

void          ONError (void )           /* Error */

{

printf (“*** Error *** \n”);

}

ករណី Function គμាន Declaration Value : នោះ Function, នឹងមានតំលៃ int ។

Ex: Declaration Function ដែលគμានប្រភេទ Function Name (float x );

IV.  Declaration និងបណ្ដា  ឧទាហរណ៏   ៖

+ លំដាប់ក្នុងការ declaration :

ពិនិត្យឧទាហរណ៌ខាងក្រោម ៖

Example :

# include <stdio.h>

# include <conio.h>

/* Declaration Function before Function main */

float f_Exam (float x, int b, int c)

{ float value ;   /* Declaration local variable */

value = x * x + b * x + c;

return (value );

}

main ( )

{

/* float f_Exam (float, int, int ); មិនបាច់មាន prototype ទេ */

float x = 1.5;

float y , z;

int    n = 3 , p =5, q =10 ;

y = f_Exam ( y, n, p ) ;

printf (” Value of y = %f \n”,y); z = f_Exam (x + 0.5, q , n-1); printf (“Value of y = %f \n”,z ); getch ( );

return (0)

}

+ Example គណនា n! = 1.2.3…. .(n-1).n

# include <stdio.h>

# include <conio.h>

long int factorial (int n)

{ int i;

long int FF = 1;

if (n>1 )

for (i = 2; i < =n; i ++) FF * = i;

return (FF);

}

main ( )

{ int n;

/* Read number n */

printf (“\n n = ”); scanf (“%d”, &n ) ;

 

/* printf the result */

printf (“\n n! = %ld \n “, factorial (n) );

getch ( );

return (0) ;

}

+ Example : ប្ដូរពីអក្សរធមμតាទៅជាអក្សរពុម្ព,ដោយប្រើប្រមាណវិធីលក្ខខ័ណ្ឌ  ។

# include <stdio.h>

# include <conio.h>

char converttocapital (char ch )

{ char c2;

c2 = ( ch> = ‘a’ && ch < = ‘z’) ? ( ‘A’- ‘a’ + ch ): ch;

return (c2);

}

main ( )

{ char smallchar , capital;

clrscr ( );

printf (“Enter a character :”); scanf (“%c”, &smallchar );

capital = converttocapital (smallchar ); printf ( “\n the capital is %c \n \n”, capital); getch ( );

return (0 );

}

Example :   convert capitaltosmallchar : ( ដោយប្រើ if statement )

# include <stdio.h>

# include <conio.h>

char converttosmallchar (char ch )

{

if (ch > = ‘a’&& ch < = ‘z’)

return ( ‘A’ – ‘a’ + ch );

else

return (ch);

}

Example : អនុគមន៏សេស គូ ៖  កំណត់ចំនួនមួយ តើជាចំនួនសេស ឬ គូ

even (n)

int n;

{

int result;

if ( (n %2 ) = = 0)

result = 1;

else

result = 0;

return ( result );

}

ឬមួយកំណត់ចំនួនមួយជាចំនួនគូ ឬ ចំនួនសេស, យើងអនុវត្ដន៏ ប្រមាណវិធី AND តាម bit វិញ ៖

if ( (n&0 x 01 ) ==0 )

result = 0;

else

result = 1;

V. បញ្ចូល parameter  អោយ sub-program :

ការបញ្ចូល parameter អោយ Function ក្នុង Turbo C ត្រូវបាន អនុវត្ដន៏ តាមរបៀបតែមួយគត់ ៖

+  បញ្ចូល Value parameter, មានន័យថា តំលៃរបស់ parameter ពិត, មុននឹងក្រោយពេលហៅ Function នោះមិនប្រែប្រួលតំលៃទេ ។

ពិនិត្យឧទាហរណ៌ខាងក្រោម ៖

# include <stdio.h>

# include <conio.h>

main ( )

{ void swap ( int a, int b);        /* prototype */

int n = 10, p = 20;

printf ( “\n Before call Function : %d %d \n”, n, p);

swap ( n, p);

printf ( “\ n After call Function: %d %d \n”, n, p);

getch ( );

return (0);

}

void swap (int a, int b);

{

int t;

printf ( “Befor swap : %d %d \n”, n, b);

t = a; a = b; b = t;

printf (“After swap : %d %d \n”, a, b );

}

Before call Function :   10        20

Before swap     :           10        20

After swap       :           20        10

 

After call Function :     10        20   មិនប្រែប្រួលតំលៃ   បើធៀបនឹងតំលៃមុនពេល   Call

Function

+     វិភាគ  ៖  Function  swap  ទទួលតំលៃពីរពី  parameter  ពិត  (n,p)  ដែលសមមូល  និង parameter រូបភាពពីរទៀតគឺ (a, b) ។   វានឹងអនុវត្ដន៏ការប្ដូតំលៃពី parameter (a, b) ខាងលើ ។ តែបន្ទាប់ មកយើងឃើញថា នៅពេលត្រឡប់ទៅ main program វិញនោះ តំលៃ របស់ parameter ពិតទាំងពីរនៅដ៏ដែល ដោយមិនប្រែប្រួល តំលៃទេ (n,p ) ។

–   ដូច្នេះនៅពេល call sub program, តំលៃ n និង p នឹងត្រូវបាន បញ្ចូន ទៅអោយ parameter

រូបភាព  a,  b  ជាបណ្ដោះអាសន្នសិន, ហើយ Function  swap  នឹងប្ដូរតំលៃ a  និង  b  ជាមួយគ្នាដោយខ្ចី variable ជួយក្នុងការប្ដូរ តំលៃនេះ ។  បន្ទាប់មកតំលៃរបស់ n, p មិនត្រូវបានប្រែប្រួលទេ, នេះជាលក្ខណៈមិនតំរូវទៅតាមតំរូវការរបស់យើង ព្រោះយើង ចង់ប្ដូរ តំលៃ n និង p មិនមែនចង់ប្ដូរតំលៃ parameter រូបភាព a, b នោះទេ ។

–        យើងនិងឃើញថាការប្ដូរតំលៃនៃពីរ  (ឬច្រើន    )    parameter   ដោយប្រើ   Function អាចប្រព្រឹតទៅបាន តាមការបញ្ជូនជាតំលៃ Address របស់ parameter ពិតទៅអោយ parameter រូបភាព

(មិនមែនបញ្ចូល Value ទេ)។

នោះគឺក្នុងករណី Function scanf   ។   បើចង់ Read តំលៃ x យើងត្រូវប្រើ Address របស់ x ដើម្បីបញ្ជូនទៅអោយ Function  scanf : scanf ( “%f”, &x ); មុននិងក្រោយការ call Function scanf, តំលៃ Address  របស់  Variable  គμានប្រែប្រួល,  តែយើងប្រើតំលៃ Address នេះដើម្បីប្រែប្រួលតំលៃខាងក្នុងវា ។   យើងនិង និយាយ ឡើង វិញ  នូវបណ្ដាបញ្ហានេះ  នៅពេលយើងរៀន pointer  ។  តែ ដើម្បី អោយយើងចេះប្រើ  Function  swap  ដូច្នេះយើងសរសេរ  Function  នេះនៅក្នុង Chapter នេះទោះបីមានប្រើ pointer ក៏ដោយ ៖

Example :   សរសេរកមμវិធីប្ដូរតំលៃពីរ  Variable n,p ដោយប្រើការបញ្ជូន Value Address

ទៅអោយ Function :

# Include <stdio.h>

# Include <conio.h>

main ( )

{ void swap (int *a, int *b );

int n = 10; p = 20;

clrscr  ( ) ;

printf (” \n Before Call Function : %d %d \n”, n, p);

swap ( &n, &p);

printf ( “\n After Call Function : %d %d \n”, n, p );

getch ( );

return (0);

}

void swap (int *a, int *b)

{ int t.

printf ( “\n Before swap : %d %d”, *a, *b);

t = *a;

*a = *b;

*b = t;

printf (“\n After swap : %d %d”, *a, *b);

}

Before Call Function 10 20
Before swap 10 20
After swap 20 10
After Call Function 20 10

ពេលនេះទើបត្រូវបានប្ដូរតំលៃនៃ Variable n, p ពិតប្រាកដមែន ។

Note:*a  ជាសញ្ញានៃតំលៃដែលរក្សាទុកក្នុង Memory និង មាន Address a ។ &a ជាសញ្ញានៃ Address memory ផ្ទុកតំលៃ a .

IV. ដែនកំនត់របស់អថេរ  ៖អថេរក្រៅ   (Global Variable)

គឺជាអថេរដែលអាចអោយយើងប្រើប្រាស់បានគ្រប់ទីកន្លែងទាំងអស់ក្នុងកមμវិធី។ ចូរពិនិត្យមើលកមμវិធី Prog5_7.C ខាងក្រោម  ៖

/* កមμវិធី Prog5_7.C */

#include <stdio.h>

#include <conio.h>

int n ; /*ប្រកាសអថេរក្រៅ n*/

void main()

{

void myfunction(void); /* ប្រកាសទំរង់ទូទៅរបស់ myfunction */

n = 1; /* ភ្ជាប់តំលៃអោយ  n = 1 */

clrscr();

/* ប្រើរង្វិល while ដើម្បីហៅ myfunction ចំនួន  4 ដង */

while(n<5) myfunction();

/* បង្ហាញតំលៃ  n ក្រោយពេលហៅ myfunction */ printf(“\nAfter called myfunction n = %d”, n); getch();

}

/* ប្រកាសរូបរាងពិតរបស់អនុគមន៍ */

void myfunction(void)

{

/* បង្ហាញតំលៃ  n លើអេក្រង់  */

printf(“\n The value of global variable n = %d”,n);

n++; /* បង្កើន  n ឡើងថែមមួយតំលៃទៀត */

}

លទ្ធផលលើអេក្រង់គឺ ៖

The value of global variable n = 1

The value of global variable n = 2

The value of global variable n = 3

The value of global variable n = 4

After called myfunction n = 5

ក្នុងកមμវិធី Prog5_7.C ខាងលើនេះមានអថេរ n ជាអថេរក្រៅ (Global Variable) ព្រោះវាត្រូវបានប្រកាសនៅ ខាងក្រៅ អនុគមន៍ ទាំងអស់ ដែលរួមទាំងអនុគមន៍ main ផងដែរ (គឺគμាន ស្ថិតនៅ ក្នុង អនុគមន៍ណាមួយឡើយ)។ ក្នុងនោះ អ្នកក៏បានឃើញដែរ ថា អ្នកមាន លទ្ធភាពអាចប្រើអថេរ n ក្នុងអនុគមន៍ myfunction ដោយគμាន កំហុសអ្វី ទាំងអស់ ដែលនេះគឺជាចំណុចល្អផង និងមិនល្អផង។ ចំណុច ល្អត្រង់ថា យើងអាចប្ដូរតំលៃ របស់អថេរនៅក្រោយពេលហៅ អនុគមន៍ មក ប្រើ និងមិនល្អត្រង់ថា ដោយសារតែភាពអាច ប្ដូរតំលៃ បាន នៅគ្រប់ទីកន្លែងបែបនេះហើយ ដែលអាចធ្វើអោយមានបញ្ហានៅ ពេលក្រោយ ជាពិសេសក្នុងកមμវិធីដ៏ធំមួយ បើសិនជាអ្នកប្រើ n នៅ ក្នុងអនុគមន៍ណាមួយ នោះ តំលៃរបស់  n នឹងមានការប្រែប្រួល ដែល នេះជាហេតុអាចឈានទៅដល់ការមាន កំហុសក្នុងកមμវិធី ដោយ ពុំបានដឹងថា តើតំលៃ n ពេលនេះត្រូវបានប្រែប្រួលដោយសារ អនុគមន៍ មួយណា។ ដែនកំនត់របស់អថេរក្រៅ ដែនកំណត់របស់អថេរ បានន័យថា ជាតំបន់ដែលអថេរនោះអាចមានសកមμភាពទៅ ដល់ បាន។ ដែនកំណត់របស់អថេរក្រៅគឺ ពេញកមμវិធីរបស់អ្នក ដោយគិត ចាប់ពីកន្លែងដែលបានប្រកាសអថេរនោះរហូតទៅដល់ខាងចុងបញ្ចប់នៃ កមμវិធី។

ឧទាហរណ៍ ៖

void main()

{

———-

———-

}

int n ; /* ប្រកាសអថេរក្រៅ */

float x ;

function1(—)

{

——–

}

function2(—)

{

——–

}

សំរាប់ពេលនេះយើងឃើញថា អថេរ n និង x អាចប្រើនៅក្នុង function1 និង  function2 បានតែពុំអាចប្រើនៅក្នុង main បាន ឡើយ ព្រោះវាត្រូវបានប្រកាសនៅខាង ក្រោយអនុគមន៍ main។ យើងអាចប្រកាសអថេរក្រៅនៅត្រង់កន្លែងណាមួយនៃកមμវិធីក៏បាន តែដើម្បីងាយស្រួលដល់ការពិនិត្យមើល និងស្វែងរក អ្នកសរសេរ កមμវិធី គួរតែប្រកាសអថេរក្រៅនៅខាង ដើមនៃកមμវិធី (ផ្នែកខាងលើ នៃកមμវិធី ដែលស្ថិតនៅក្រោមការប្រកាស header file)។

*        អថេរដំបន់   (Local Variable) ជាអថេរដែលមាន សកមμភាព (ឬអាចប្រើបាន) តែនៅក្នុងអនុគមន៍ដែលបានប្រកាស វាតែប៉ុណ្ណោះក្រោយពេលអនុគមន៍ត្រូវបានបញ្ចប់ នោះបណ្ដាអថេរ ដំបន់ដែលបានប្រកាស ក្នុងអនុគន៍នោះក៏ត្រូវបានរំដោះចេញពី Memory វិញដែរ។ចូរពិនិត្យមើលកមμវិធី Prog5_8.C ខាងក្រោមនេះ មានបង្ហាញអំពីការប្រើប្រាស់អថេរ ដំបន់ (Local Variable)។

/*—– កមμវិធី Prog5_8.C—–*/

#include <stdio.h>

#include <conio.h>

/* ប្រកាសអថេរក្រៅ */

int x;

float y = 5.5;

/* ប្រកាសទំរង់ទូទៅរបស់អនុគមន៍ */

void F1();

void F2();

void main()

{

clrscr();

x = 10;

printf(“x = %d y = %f”, x, y); F1();

F2();

printf(“\n\nAfter called functions x = %d”, x);

getch();

}

void F1()

{
printf(“\nCall in F1, x gloable = %d”, x);

printf(“\nCall in F1, y gloable = %f”, y);

}

void F2()

{    int a = 50;

printf(“\nCall in F2, a + x = %d + %d = %d”, a, x, a+x);

x = x + a; /* ផ្លាស់ប្ដូរតំលៃរបស់អថេរក្រៅ x */

}

លទ្ធផលលើអេក្រង់ ៖

x = 10 y = 5.500000

Call in F1, x gloable = 10

Call in F1, y gloable = 5.500000

Call in F2, a + x = 50 + 10 = 60

After called functions x = 60

ក្នុងកមμវិធីខាងលើយើងឃើញថា អថេរក្រៅ  x និង y អាចយកទៅ ប្រើបានគ្រប់ទី កន្លែង (បានគ្រប់ក្នុងអនគមន៍) ដោយឡែកអថេរដំបន់ a ដែលបានប្រកាសក្នុងអនុគមន៍ F2 វិញ ពុំត្រូវបានអនុញ្ញាតអោយ យក ទៅប្រើនៅក្នុងអនុគមន៍ផ្សេងដូចជា F1 ឬក៏ main បានទេ គឺអាចប្រើ បានតែក្នុងអនុគមន៍ដែលបានប្រកាសវាតែប៉ុណ្ណោះ ក្នុងករណី ឈេμាះ ដូចគ្នា  តើអថេរដំបន់អាចច្រឡំជាមួយអថេរក្រៅដែរឬទេ?

ដើម្បីបកស្រាយអោយសំណួរនេះ ចូរពិនិត្យមើលកមμវិធី Prog5_9.C ខាងក្រោម ដែលក្នុងនោះមានការប្រកាសអថេរ m និង n ជាអថេរក្រៅផង និងជាអថេរដំបន់របស់ អនគមន៍ផ្សេងៗទៀតផង។

/*—— កមμវិធី Prog5_9.C ——*/

#include”stdio.h”

#include”conio.h”

/* ប្រកាសអថេរក្រៅ n និង m */

int n = 20;

int m = 50;

void main()

{

/* ប្រកាសទំរង់ទូទៅរបស់អនុគមន៍ */

void fun1();

 

void fun2();

void fun3();

int m = 10; /* ប្រកាសអថេរដំបន់ m */

clrscr();

printf(“\nm in main = %d”, m);

fun1(); fun2(); fun3(); getch();

}

void fun1()

{

int m = 11;

printf(“\nm in fun1 = %d”,m);

}

void fun2()

{   int n = 30;

printf(“\nn in fun2= %d”,n);

}

void fun3()

{

printf(“\nm globle = %d”,m);

printf(“\nn globle = %d”,n);

}

លទ្ធផលលើអេក្រង់គឺ ៖ m in main = 10 m in fun1= 11

n in fun2 = 30 m globle = 50 n globle = 20 តាមរយៈ ឧទាហរណ៏ ខាងលើនេះ អថេរ n និង m ដែលបានប្រកាសក្នុងអនុគមន៍ fun1

គឺមានឥទ្ធិពលតែក្នុងអនុគមន៍នោះតែប៉ុណ្ណោះ បានន័យថាយើងពុំអាច យកអថេរទាំងនោះទៅប្រើនៅខាងក្រៅដែនកំនត់របស់វាបានឡើយ។ ក្នុងអនុគមន៍ fun1 និង fun2 មានប្រកាស អថេរ m ដូច្នេះពេល នេះ គ្រប់ឈេμាះ m ក្នុងអនុគមន៍ fun1 គឺជាអថេរដំបន់ របស់ fun1

មិន មែនជាអថេរដំបន់របស់អនុគមន៍ main ទេ ហើយក៏មិនមែន ជាអថេរក្រៅ ដែរ។ ដើម្បីជាការងាយយល់យើងអាចនិយាយថា នៅក្នុងស្រុកមួយមានមនុស្សបីនាក់ ដែលមានឈេμាះដូចគ្នាគឺ
“ក” តែរស់នៅផ្ទះផ្សេងគ្នាឧបមាថាផ្ទះ A, B និង C។ ដេូ ចះ្ន ប្រសនិ

បើក្នុងផ្ទះ  A មានការហៅឈេμាះ “ក” នោះប្រាកដជាសំដៅទៅ លើឈេμាះ “ក”  ដែលរស់  នៅក្នុងផ្ទះ A នោះហើយ គឺមិនមែន សំដៅ ទៅលើអ្នកដែលរស់ក្នុងផ្ទះផ្សេងនោះទេ។ ក្នុងកមμវធិីដចូ

ខាងលើ តើអថេរក្រៅ  m និងអថេរដំបន់ m អាចច្រឡំគ្នាបានដែរឬទេ? ការហៅឈេμាះ m មកប្រើក្នុងករណីនេះ ប្រសិនបើឈេμាះ m នោះបានប្រកាសក្នុង អនុគមន៍នោះនាំអោយវានឹងប្រើអថេរ ដំបន់ m នោះតែម្ដង (បានន័យថាពេល Compile វានឹងជំនូសកន្លែង m

ក្នុងអនុគមន៍នោះដោយអាសយដ្ឋាន Memory របស់អថេរដំបន់ m) ជាក់ស្ដែងដូចក្នុងអនុគមន៍ fun1 និង fun2។ ប្រសិនបើមាន ប្រើ ឈេμាះអថេរ m នោះ តែមិនបានប្រកាសក្នុងអនុគន៍នោះទេ នោះ Compiler នឹងពិនិត្យរកមើលថា តើឈេμាះ m នោះមាន ប្រកាស ជាអថេរក្រៅដែរឬទេ បើមានវានឹងប្រើអរថរក្រៅ m នោះ (ជាក់ ស្ដែង ដូច ក្នុងអនុគមន៍ fun3 មានប្រើអថេរ m និង n) តែបើគμានទេវានឹង ប្រាប់កំហុសភ្លាម (undefined symbol m in module…)។

*        អថេរដំបន់ស្ដាទិក   (Static local variable)

យើងអាចអោយកុំព្យូទ័រផ្គត់ផ្គង់ Memory ក្នុងដំបន់  Static អោយទៅ អថេរ ដំបន់ ដោយគ្រាន់តែប្រើពាក្យគន្លឹះ static ពីខាងមុខការ ប្រកាស អថេរ ដំបន់នោះតែប៉ុណ្ណោះ។ ពេលនេះទិន្នន័យ របស់អថេរ ដំបន់នោះ នឹងត្រូវបានរក្សាទុកក្នុង Memory រហូតទោះជា អនុគមន៍បាន បញ្ចប់ ក៏ដោយ។ ដើម្បីស្វែងយល់អំពីពាក្យគន្លឹះ static នេះអោយកាន់តែ ច្បាស់លាស់ នោះចូរមើលក្នុងចំណុចទី I.3 នៃមេរៀនទី  12 (ទំព័រទី 482)។កមμវិធី Prog5_10.C ខាងក្រោមនេះ បង្ហាញអំពីដំណើរការ របស់អថេរដំបន់ ស្ដាទិក (Static Local Variable)។

/*——— កមμវិធី Prog5_10.C ———*/

#include <stdio.h>

#include <conio.h>

void main()

{   void fun(void); /* ប្រកាសទំរង់ទូទៅរបស់អនុគមន៍ fun */

int n ; /* អថេររាប់រង្វិលជុំ for */

/* ប្រើរង្វិល for ដើម្បីហៅអនុគមន៍ fun ចំនួន  5 ដង */

for(n = 1 ; n <=5 ; n++)

fun();

getch( );

}

void fun(void)

{   static int i; /* ប្រកាសអថេរដំបន់ស្ដាទិក i */

i++;

printf(“\nCall in the %d time”, i);

}

លទ្ធផលលើអេក្រង់គឺ ៖

Call in the 1 time

Call in the 2 time Call in the 3 time Call in the 4 time Call in the 5 time

ក្នុងកមμវិធី Prog5_10.C ខាងលើនេះ អថេរ i ត្រូវបានប្រកាសជា អថេរដំបន់ ស្ដាទិកក្នុងអនុគមន៍ fun ដូច្នេះហើយបានជាយើងឃើញថា ការហៅអនុគមន៍ fun ចំនួន  5 ដងដោយអនុគមន៍ main

បានធ្វើ អោយ តំលៃរបស់អថេរដំបន់ស្ដាទិក i ប្រែប្រួលជានិច្ច (ដោយសារ Statement i++; ក្នុងអនុគមន៍ fun)។ ជាធមμតាចំពោះ អថេរដំបន់ក្នុង អនុគមន៍ណាមួយ ក្រោយពេលដែលអនុគមន៍ នោះ ត្រូវបានអនុវត្ដចប់ នោះបណ្ដាអថេរ ដំបន់របស់អនុគមន៍នោះក៏ត្រូវ បាន រំដោះចេញពី Memory ដោយស្វ័យប្រវត្ដិដែរ ឬបានន័យ ថា បណ្ដាទិន្នន័យដែលកំពុងតែរក្សាទុកដោយបណ្ដាអថេរដំបន់ទាំងនោះ ត្រូវបានបាត់បង់។ ចំពោះអថេរដំបន់ស្ដាទិកវិញ មានលក្ខណៈ ខុសពី អថេរដំបន់បន្ដិចត្រង់ថា Memory ដែលបានផ្គត់ផ្គង់អោយអថេរ ដំបន់ ស្ដាទិក នឹងពុំត្រូវបានរំដោះចេញវិញឡើយ ទោះបីជា អនុគមន៍ដែល បានប្រកាស អថេរដំបន់ស្ដាទិកនោះបានអនុវត្ដចប់ក៏ដោយ ឬបាន ន័យថាទិន្នន័យដែលត្រូវបានរក្សាទុកដោយអថេរដំបន់ស្ដាទិក នឹងពុំ ត្រូវ បាត់បង់ឡើយក្នុងខណៈដែលអនុគមន៍ដែល បានប្រកាស អថេរដំបន់ស្ដាទិកនោះពុំត្រូវបានអនុវត្ដក៏ដោយ ហើយកុំព្យូទ័រ នឹងរក្សាទុកទិន្នន័យនោះដរាបណាកមμវិធីទាំងមូលត្រូវបានបញ្ចប់។ ដូចដែលអ្នកបានឃើញ លទ្ធផលរបស់កមμវិធី Prog5_10.C ខាងលើនេះ នៅពេលដែល i ត្រូវបានប្រកាសជា អថេរដំបន់ស្ដាទិក និងមិនទាន់បានភ្ជាប់តំលៃកំណត់ណាមួយអោយវានោះ ពាក្យគន្លឹះ static និងភ្ជាប់តំលៃសូន្យអោយទៅ i ដោយស្វ័យ ប្រវត្ដិ លុះដល់ ពេលជួប i++; នោះតំលៃរបស់ i ត្រូវបានកើនឡើងមួយ តំលៃថែម ទៀត (ពេលនេះ i=1)។ ក្រោយការហៅអនុគមន៍ fun ដោយ main នៅជុំទីមួយ តំលៃរបស់  i ត្រូវបានប្រែប្រួលសេμី 1 លុះដល់ ពេល ជួបការហៅ ជាថμីទៀតនៅជុំទីពីរ តំលៃរបស់  i ក៏ត្រូវបូកថែម មួយ ទៀត  ដែលពេលនេះធ្វើអោយ i = 2 (ព្រោះក្រោយការហៅ លើក ទីមួយ i = 1) ហើយជាបន្ដបន្ទាប់នៅជុំទី 3, 4 និង 5 តំលៃ របស់ i ក៏ត្រូវបានកើនឡើងតាមលំដាប់គឺ 3, 4, 5 ដែរ។ តំលៃរបស់  i ពេលនេះគឺ 5 ហើយ  តំលៃនេះនឹងរក្សាទុកក្នុង Memory រហូត ដល់ ពេលដែលកមμវិធីបានបញ្ចប់។

 ចំណាំ  ៖ អថេរក្រៅអាចរក្សាទុកទិន្នន័យបានពេញដំណើរការនៃ កមμវិធី   ឬបានន័យថា  Memoryដែលបានផ្គត់ផ្គង់អោយ អថេរក្រៅ  ពុំត្រូវបានរំដោះវិញឡើយដរាបណាកមμវិធី  នៅតែដំណើរការ។

យើងអាចប្រើអថេរក្រៅបាននៅគ្រប់ទីកន្លែងទាំងអស់នៃកមμវធិ
ី ដោយ ចាប់ពីកន្លែងដែលបានប្រកាសវាទៅ។

*    អថេរដំបន់អនុញ្ញាតអោយប្រើបានតែនៅក្នុងតួអនុគមន៍ដែលបាន ប្រកាសវាតែប៉ុណ្ណោះ ហើយទិន្នន័យដែលវាបានរក្សាទុក នឹងត្រូវបាត់ បង់នៅពេលណាដែលអនុគមន៍ ដែលបានប្រកាសអថេរ ដំបន់នោះ បាន បញ្ចប់។*        អថេរដំបន់ស្ដាទិក   អនុញ្ញាតអោយយើងប្រើវាបាន តែក្នុង តួអនុគមន៍ដែលបាន ប្រកាសវាតែប៉ុណ្ណោះនិងទិន្នន័យ ដែលវា កំពុងរក្សាទុកពុំត្រូវបានបាត់បង់ឡើយ   គឺទិន្នន័យ    នោះនឹង ត្រូវបានរក្សាទុករហូតដល់ពេលណាដែលកមμវិធីទាំងមូលត្រូវបាន បញ្ចប់។

VII. លក្ខណៈ Recursion នៃ  Sub-program :

Function អាចហៅខ្លួនឯងមកប្រើបាន, លក្ខណៈនេះហៅថា Recursion ។

ឧទាហរណ៌ ៖ គណនាតំលៃ N!

n ! = 1. 2. 3….(n-1) . n

ឬតាមនិយមន័យ

n ! =
1      ពេល n = 0

(n-1) !.n

ពេល
 n >= 1

ដូច្នេះ Function Factorial អាចកំណត់ដូចខាងក្រោម ៖

int Factorial (int n )

{

if ( n ==0 ) return (1);

else return ( n* Factorial (n-1));

}

Example:

# include < stdio.h>

# include <conio.h>

long int Factorial (int n );          /* Function prototype */

main ()

{ int n ;

printf (“\n

n =”); scanf (“%d”, &n) ;

printf (“ n! = %ld \n”, Factorial (n));

getch();

return (0 );

}

long int Factorial (int n)

{ if ( n == 0) return (1);

else return ( n* Factorial ( n – 1));

}

*Note :   លក្ខណៈ Recursion ត្រូវប្រើ memory   ប្រភេទ

ដើម្បីផ្ទុកលទ្ឋផល បណ្ដោះអាសន្ន ។

LIFO ( Last In, First Out, stack )

Example :  គណនា PGCD នៃពីរចំនួន x, y តាមនិយមន័យខាងក្រោម ៖

PGCD (x, y) = x         បើ y = 0

= PGCD (y, x/y)

ដូច្នេះ PGCD អាចគណនាដូចខាងក្រោម ៖

int PGCD (int x, int y)

{

បើ y < > 0

if ( y == 0) return (x) ;

else return (PGCD ( y, x %y));

}

តែ program ខាងក្រោមនេះមានល្អជាងខាង Algorithme, ទោះបីជាវាមានជាងក៏ដោយ ៖

int PGCD (int x, int y )

{ int number;

while ( y != 0)

/* សំណល់ */

{ number = x %y;

x = y;

y = number;

}

return (x);

};

+  ដូច្នេះយើងពុំគម្បីប្រើ Recursion នៅពេលដែលយើងអាចប្រើ looping ដើម្បីគណនាលំហាត់នោះ ។

 VIII.   ម៉ាក្រូ    (Macro)

ក្រៅពីអនុគមន៍ ភាសា C នៅមានអង្គកំណត់ទិស (Directive Compiler) មួយ ប្រភេទដែលអាចជួយ អោយយើង ចាកផុតពី ភាពសμុគសμាញ និងអាចសន្សំបាននូវពេលវេលា នោះ គីការប្រើម៉ាក្រូ។

VIII.1. និយមន័យ(Macro) ម៉ាក្រូអាចជាសំណុំនៃ Statement និងកន្សោម ដែលត្រូវបានតំណាងដោយឈេμាះ ណាមួយ។ ក្នុង លំនាំនៃការ Compile បើសិនជា Compiler បានជួបបណ ្ដា ឈេμាះ ម៉ាក្រូ នោះវានឹងជំនួសកន្លែងឈេμាះ ម៉ាក្រូនោះ ដោយបណ្ដា Statement ដើមរបស់វា រួចទើប  អនុវត្ដន៍ការ Compile ជាក្រោយ។


VIII.2. របៀបប្រើ  ម៉ាក្រូ    (How to Use Macro)

ទំរង់ទូទៅនៃការប្រកាសម៉ាក្រូ ៖

#define9ឈេμាះម៉ាក្រូ9បណ្ដុំនៃ Statementចូរពិនិត្យមើលបណ្ដាឧទាហរណ៍ខាងក្រោមនេះ សុទ្ធតែជាកមμវិធីបង្ហាញអំពីរបៀប ប្រើប្រាស់ម៉ាក្រូ។

/*—— កមμវិធី Prog5_11.C ——-*/

#include <conio.h>

#include <stdio.h>

/* ប្រកាសម៉ាក្រូ Msg*/

#define Msg printf(“\nWelcome to you”)

/* ប្រកាសម៉ាក្រូ Ext*/

#define Ext “\nPress any key to exit the program !”

void main()

{

clrscr();

Msg;

printf(“\nHow to use macro in C”);

printf(Ext);

getch();

}

លទ្ធផលលើអេក្រង់គឺ ៖

Welcome to you

How to use macro in C

Press any key to exit the program !

នៅពេល C Compiler ចាប់ផ្ដើមការ Compile នោះជួបជាមួយ ការប្រកាសម៉ាក្រូ ពីរគឺ Msg តំណាងអោយឃ្លា printf(“\nWelcome to you”) និង Ext តំណាងអោយ “\nPress any key to exit the program !”។ នៅពេល Compile មកដល់ក្នុងអនុគមន៍ main

 

ក៏បានជួបជាមួយការហៅឈេμាះម៉ាក្រូមកប្រើគឺ Msg; និង printf(Ext);។ នៅពេល ជួប Msg នោះ Compiler ពុំទាន់  Compile ទេ វាត្រូវជំនួសសំណុំ Statement ដើមគឺ printf(“\nWelcome to you”); សិន (ដែលសំណុំ Statement ដែលបានជំនួសចូលពេល នេះគឺជា  Statement ដែលមានមុខងារបង្ហាញឃ្លា


“Welcome to you” លើអេក្រង់)  រួច ទេបី

Compile បន្ដទៀត។ ក្នុងខណៈដែល Compile

មកដល់ការប្រើម៉ាក្រូ Ext ពេលនោះ Compiler ក៏ត្រូវអនុវត្ដ ដូច ពេលជួបឈេμាះម៉ាក្រូមុននេះដែរ

គឺជំនួសឈេμាះ Ext ដោយសំណុំ Statement ដើម ដែលពេលនេះគឺ “\nPress any key to exit the

program !”។ ក្រោយ ពេលជំនួសចូលរួចទើប Compiler ធ្វើការ Compile Statement នោះ។

ដើម្បីកាន់តែ  ច្បាស់ថែមទៀតអំពីការជំនួសម៉ាក្រូដោយសំណុំ Statement ដើមនោះ ចូរពិនិត្យមើលរូប ខាងក្រោមនេះ ៖

ខាងក្រោមនេះជាកមμវិធីមួយទៀត ដែលបង្ហាញអំពីការ ប្រើ ម៉ាក្រូក្នុងទំរង់មួយប្រហាក់ប្រហែលទៅនឹងការប្រើអនុគមន៍។

/*—– កមμវិធី Prog5_12.C ——*/

#include <stdio.h>

#include <conio.h>

#define num 3

#define print(a) printf(“The result of calculation is %d”, a)

#define calculate(y) ((y)*(y)*(y))

void main()

{   int x , z ; /* ប្រកាសអថេរ x និង z */

x = num; /* ពេលនេះយើងបាន x = 3 */

z = calculate(x) ; /* ហៅម៉ាក្រូ calculate យើងបាន z = 27 */

 clrscr();

print(z) ; /* ហៅម៉ាក្រូ printf */

getch();

}

លទ្ធផលលើអេក្រង់គឺ ៖

The result of calculation is 27

នៅក្នុងកមμវិធី Prog5_12.C ខាងលើនេះមានការប្រកាសម៉ាក្រូចំនួនបីគឺ num, print(a) និង

calculate(y)។ កង្ន
អនុគមន៍ main ការហៅម៉ាក្រូលើកទីមួយគឺ x = num ដែលពេលនោះ Compiler

ត្រូវជំនួសកន្លែង num នោះដោយតំលៃ 3 រួចហើយក៏ភ្ជាប់ អោយទៅ x ទើបនាំអោយ x = 3។ ជាមួយម៉ាក្រូពីរទៀតគឺ ៖

1.     print(a)

Ö      នោះអង្គកំណត់ទិស #define នឹងបំលែងទៅជា

printf(“The result of calculation is %d”, a)

ឧបមាថាគេហៅម៉ាក្រូនេះប្រើដូចខាងក្រោម ៖

print(3)

ពេលនោះអង្គកំណត់ទិស #define នឹងបំលែងទៅជា ៖

printf(“The result of calculation is %d”, 3)

2.     calculate(y)

Ö      នោះអង្គកំណត់ទិស #define នឹងបំលែងទៅជា

((y)*(y)*(y))

ឧបមាថាគេហៅម៉ាក្រូនេះប្រើដូចខាងក្រោម ៖

calculate(3);

ពេលនោះអង្គកំណត់ទិស #define នឹងបំលែងទៅជា ៖

((3)*(3)*(3))

ពេលនេះយើងឃើញថា ជាមួយនឹងការប្រើម៉ាក្រូបែបនេះ គឺមាន លក្ខណៈប្រហាក់ ប្រហែលទៅនឹងការប្រើប្រាស់អនុគមន៍ដែរ ក៏ប៉ុន្ដែ ចូរកុំចាត់ទុកថា នេះគឺជាអនុគមន៍អោយ សោះ។ អ្នកក៏អាច ប្រកាសប្រើ ម៉ាក្រូបានដូចទំរង់ខាងក្រោមនេះ ៖

ឧទាហរណ៍ថា ៖

#define product(m, n) ((m)*(n))

ឧបមាថាក្រោយពេលប្រកាសរួច ក្នុងកមμវិធីអ្នកបានប្រើ ៖

result = product(x, y+1)

នៅពេលនោះអង្គកំណត់ទិសនឹងអោយ Compiler បំលែងទៅជា ៖

result = ((x)*(y+1))

ª    ចូរប្រយ័ត្នក្នុងការប្រើប្រាស់ម៉ាក្រូ    ៖

នៅខាងចុងបំផុតរបស់អង្គកំណត់ទិស #define គμានសញ្ញាចុចក្បៀស (;) ទេ។

*      អ្នកត្រូវសរសេរធាតុនីមួយៗនៅក្នុងរង្វង់ក្រចកអោយបាន ច្បាស់បើសិនជាមិនសរសេរក្នុងរង្វង់ក្រចកទេ នោះអាចនាំអោយ មានការជំនួសខុស។

ឧបមាថាអ្នកប្រកាស ៖

#define calculate(y) (y*y*y)

បន្ទាប់មកអ្នកមានហៅប្រើ ៖

calculate(a+b)

នៅពេលនោះអង្គកំណត់ទិសបានបញ្ជាអោយ Compiler បំលែងទៅជា ៖

a+b*a+b*a+b

ដែលលទ្ធផលនេះខុសពីការចង់បានរបស់អ្នក ពីព្រោះលទ្ធផល ដែលអ្នករងចាំគឺ ៖

(a+b)*(a+b)*(a+b)

ª      ម៉ាក្រូមួយចំនួនដែលគេច្រើនប្រើ   ៖

ក្នុងការសរសេរកមμវិធី មានម៉ាក្រូមួយចំនួនដែលតែង តែជួប ប្រទះញឹកញាប់ជាងគេ នោះ ត្រូវបានបង្ហាញនៅខាងក្រោមនេះ ៖

#define ESC 0x1B /* បង្កើតម៉ាក្រូ ESC តំណាងអោយ Key ESC ដេលមាន ASCII = 0x1B Hex

= 27 Dec*/

#define TRUE 1 /* បង្កើតម៉ាក្រូ TRUE តំណាងអោយ ភាពពិត របស់តក្ក */
#define FALSE 0 /* បង្កើតម៉ាក្រូ FALSE តំណាងអោយភាព មិនពិតរបស់តក្ក */
#define PI 3.14159 /* បង្កើតម៉ាក្រូ PI តំណាងអោយតំលៃ 3.13159 */

#define ON 1 /* បង្កើតម៉ាក្រូ ON តំណាងអោយសភាពបើករបស់ Transistor */
#define OFF 0 /* បង្កើតម៉ាក្រូ OFF តំណាងអោយសភាពបិទរបស់ Transistor */

 VIII.3. តើគួប្រើ   អនុគមន៍ ឬ  ម៉ាក្រូ

លក្ខណៈដូចគ្នារវាងម៉ាក្រូ   និងអនុគមន៍  ៖ការប្រើឈេμាះរបស់ អនុគមន៍ឬក៏ម៉ាក្រូ ធ្វើអោយអ្នកសរសេរកមμវិធីអាចធ្វើការងារ បាន យាង៉ដែលមិនត្រឹមតែសន្សំបាននូវពេលវេលលា ថែមទាំងអាច ជៀស វាងបានកំហុស មួយចំនួន និងម្យ៉ាងទៀតវាធ្វើអោយ កមμវិធី មាន លក្ខណៈ ងាយមើល ងាយយល់។ល។

*        ភាពខុសគ្នារវាងម៉ាក្រូ និងអនុគមន៍ច្រេនី

+     កមμវិធីដែលសរសេរជាមួយម៉ាក្រូ នោះត្រូវចំណាយ Memory សំរាប់  Code Segment ច្រើនជាងកមμវិធីដែល សរសេរជា មួយ អនុគមន៍  ពីព្រោះពេលជួបឈេμាះម៉ាក្រូ  នៅកន្លែងណា  នោះ Compiler នឹងជំនួសកន្លែងនោះដោយបណ្ដា Statement ដើម របស់ វា។ ដូច្នេះបើក្នុងកមμវិធីជួបឈេμាះម៉ាក្រូ n ដង នោះក៏ត្រូវជំនួស Statement ដើមរបស់វាចំនួន n ដងដែរ  ដែលនេះជាមូល ហេតុនាំ អោយក្រោយពេល Compile  រួច   កូដរបស់កមμវិធីមានប្រវែង  វែងជាងកមμវិធីដែលសរសេរជាមួយអនុគមន៍ ពីព្រោះ អនុគមន៍ ត្រូវបាន Compile តែម្ដងគត់  បន្ទាប់មកពេលជួបការហៅអនុគមន៍នោះ Compiler គ្រាន់តែជំនួសកន្លែងហៅឈេμាះ   អនុគមន៍នោះ ដោយ អាសយដ្ឋានក្នុង   Code   Segment របស់វាជាការស្រេច។

+      កមμវិធីដែលប្រើម៉ាក្រូដំណើរការលឿនជាងកមμវិធីដែលប្រើ អនុគមន៍បន្ដិចពីព្រោះវាគμានចំណាយពេលសំរាប់ការហៅ    ដូច កមμវិធី ដែលប្រើអនុគមន៍      (ចូរស្វែងយល់អំពីដំណើរការ របស់  CPU Instruction CALL នោះអ្នកនឹងបានឃើញថា នៅពេលហៅ  អនុគមន៍  តើ CPU ធ្វើការយ៉ាងដូចម្ដេច? អ្នកអាចរកមើលវាបានក្នុង បណ្ដាសៀវភៅនិយាយ អំពីភាសា Assembly)។

+      យ៉ាងណាមិញ   អ្នកគួរប្រើម៉ាក្រូតែជាមួយបណ្ដុំ  Statement   ងាយៗបានហើយ   បើបណ្ដុំStatement វែងពេក នោះ #define នឹងគμានឥទ្ធិពល (មិនអាចប្រើបាន) ឡើយ។

IX. Statement library របស់ function :ក៏ដូចជាបណ្ដាភាសាសរសេរកមμវិធីផ្សេងទៀតដែរ,    Turbo   C មានបណ្ដា   function ជាច្រើនដែលត្រូវបានកំណត់ និយមន័យជា ស្រេចក្នុង C ។ គេចែកបណ្ដា Function ទាំងនោះជាបណ្ដាក្រុមៗ ហើយទុកវាក្នុងបណ្ដា file header, ខាងក្រោមនេះ ជាបណ្ដា file standard library : stdio.h   library នៃបណ្ដា function Input / output math.h        library នៃបណ្ដា function គណិតវិទ្យា stdlib.h     library នៃបណ្ដា function update memory string.h    library នៃបណ្ដា function របស់ stringctype.h   library នៃបណ្ដា function convert character ។

 X. បណ្ដាអនុគមន៍ ដែលមានស្រាប់  (Build-in Function)
X.1. random function

+  Syntax : int  random (num) : ជា function បង្កើតបណ្ដាចំនួន Random នៅចន្លោះពី០ ដល់ num–1
+ Syntax : rand ( ): បង្កើតចំនួន Random នៅចន្លោះ ០ ដល់ 32767
+ Syntax : randomize ( ): ធ្វើអោយបណ្ដា function random ( ) និង rand ( )បង្កើតនូវបណ្ដា លេខផ្សេងៗគ្នា ។

Example :

# include <stdlib.h>

# include <stdio.h>

# include <time.h>

int main (void)

{ randomize ( ) ;

printf (” \n random in range ( 0 – 99 ): %d \n” random (100));

return (0);

}

X.2.

បណ្ដាអនុគមន៍   នៃរយៈពេល  (DateTime Function)
ជា បណ្ដា Function បង្កើតនិង Read រយៈពេល, បង្កើតនិង Read  ថ្ងៃ  – ខែ  ។  បណ្ដា Function

នេះផ្ទុក ក្នុង <DOS.H> ។

ក្នុង Turbo C កំណត់និយមន័យ ទំរង់របស់ថ្ងៃ, ខែនិងរយៈពេលដូច ខាងក្រោម ៖

* ថ្ងៃ, ខែ ៖

struct date

{

int year;           /* Current year */

char date;         /* date of the month */

char month;     /* month ( 1 = Jan ) */

};

void getdate ( struct date * datep );     (យកថ្ងៃ, ខែពី System )

void setdate (struct date * datep );      ( កំនត់ថ្ងៃខែ )

Example :  យកថ្ងៃ, ខែពី System របស់កុំព្យូទ័រ ៖

# include < dos.h>

# include <stdio.h>

# include <conio.h>

int main (void )

{ struct date d ;

getdate (&d) ;

printf (“The current year is %d \n”, d.da_year );

printf (“The current date is %d \n”, d.da_day );

printf (“The current month is: %d \n”, d.da_mon );

getch ( );

return (0);

}

Example :  កំណត់ថ្ងៃ, ខែអោយកុំព្យូទ័រ ៖

# include <process.h>

# include <conio.h>

# include < dos.h>

int main (void)

{

struct date reset ;

struct date save_date ;

getdate ( &save_date);

printf ( “day, month source : \n”);

system ( “date”);

reset.da_year = 2001

reset.da_day  = 1;

reset.da_month = 1;

setdate (&reset );

printf ( “day month have set : \n”);

system ( “date”);

setdate (&save_date );

printf (“return to day month source : \n”);

system ( “date”);

getch ( );

return (0);

}

Note: Function System ជា Function call statement DOS ។

Example : System (“dir”) ប្រើ call statement dir របស់ dos ។ Function ត្រូវ call :

# include <stdio.h>

# include <process.h>

10. c) ទំរង់ Variable នៃរយៈពេល និង បណ្ដា Function ដែលមានទំនាក់ទំនងជាមួយ struct time

{

unsigned char         /* minutes */

unsigned char

/* hours */

unsigned char ti_hund;            /*hundredths of seconds */

unsigned char ti_sec;               /* Seconds */

};

ជាមួយ Function Read និង set រយៈពេល ៖

void gettime (struct time * timep ); (Read រយៈពេល )

void  settime (struct time * timep); ( Set រយៈពេល )

Example : Function Read រយៈពេល ៖

# include <conio.h>

# include <stdio.h>

# include <dos.h>

int main (void )

{ struct time t ;

gettime (&t);

printf ( “Current time is : %2d : %02d : % 02d. %02d \n”), t.ti_hour, t.ti_min, t.ti_sec, t.ti_hund );

getch ( );

return (0 );

}

Example : Function set time:

# include <stdio.h >

# include <conio.h>

# include <dos.h>

int main (void )

{

struct time t ;

gettime (&t)

printf (“current minutes is %d \n”, t.ti_min); printf (“current hour is %d \n”, t.ti_hour); printf( “current seconds is %d \n”, t.ti_sec ); printf ( “hundredths of seconds \n”, t.ti_hund);

/* add 1 minute and call setting */

t.ti_min ++; settime (&t); getch ( ). return (0);

}

លំហាត់អនុវត្ដន៍

 

1/ ចូរសរសេរកមμវិធីដោយប្រើ Function, ដោះស្រាយ រឺសសមីការដឺក្រេទី ២ ax2 + bx + c = 0

Function សមមូលនឹងករណី delta positive, delta negative, delta zero ។

n n!
1 1
2 2
3 6
4 24
5 120
6 720
7

 

2/ ចូរសរសេរកមμវិធីដោយប្រើ Functin, សរសេរតារាង n! ដែល n = 1… 14 ក្រោយមកចូរសាកល្បងមើលប្រភេទ int តើអាចគណនាបាន ប៉ុនμានតួ ? បើ long int តើអាចគណនាបានប៉ុនμានតួ ?

3/ សរសេរកមμវិធីដោយប្រើ Function គណនា an ដែល a: Real; n : ជាចំនួនគត់វិជ្ជមាន, តាមពីររបៀប ៖

+   គណនាដោយផ្ទាល់, មិនចាំបាច់ប្រើ recursion
+    គណនាតាម recursion

4/  សរសេរកមμវិធីដោយប្រើ Function គណនាក្រលាផ្ទៃនៃបណ្ដាការ៉េ, រង្វង់, ចតុកោណកែង, ដោយបង្កើតជា

menu ដើម្បី select គណនាដូចខាងក្រោម ៖

0.   Exit program

1.   គណនាក្រលាផ្ទៃការ៉េ
2.   គណនាក្រលាផ្ទៃរង្វង់
3.   គណនាក្រលាផ្ទៃចតុកោណកែងឧ

“press select ”

5/   ចូរសរសេរ Function គណនា n! ក្រោយមកសរសេរកមμវិធី ពេញលេញដើម្បីគណនា ៖

Cnk = n! / ( k! * (n-k)!)

6/ បង្កើតស្វីត Fibonacci

ស្វីត Fibonacci ជាស្វីត F1, F2, F3, … Fn ត្រូវបង្កើតដោយប្រើរូបមន្ដ ៖

Fn  = Fn-1 + F n-2

ដែល F1 = 1, F2 = 1
ឧទាហរណ៌ 1, 1, 2, 3,5, 8, 13, 21

ចូរសរេសកមμវិធីដោយប្រើ  Function គណនា Maximum និង   minimum   នៃ 3ចំនួន Read

from Keyboard

8/ គេអោយអនុគមន៏    f(x,t)   = |a-b| (a³ + b-3)

ក្នុងនោះ

a = log3 (x² + Sin² (x) + |tg (x)| + s)b = ( ផ្នែកគត់របស់ y)

និង x,y ជា Variable ប្រភេទ Real ។

a.   ចូរសរសេរ Function គណនា f(x,y)
b.   គណនា f(x,y) ដែល x =1.234, y = 2. 345

9/     តើការបង្កើតអនុគមន៍ក្នុងការសរសេរកមμវិធី មានប្រយោជន៍យ៉ាងដូចម្ដេច?
10/    អ្វីទៅដែលហៅថា   ប៉ារ៉ាមែត្រ    និងអាគុយម៉ង់    (Argument)   ?    ចូរនិយាយ   អំពីការដោះដូរទិន្នន័យរវាងប៉ារ៉ាមែត្រ និងអាគុយម៉ង់។

11/   តើពាក្យគន្លឹះ return មានមុខងារដូចម្ដេចដែរ?

12/   ចូរអោយនិយមន័យទៅលើ ៖

*        អថេរក្រៅ (Gloable Variable)

ƒ      អថេរដំបន់ (Local Variable)

ƒ      អថេរដំបន់ស្ដាទិក (Static local variable)

13/   អ្វីទៅគឺជាម៉ាក្រូក្នុងភាសា C? តើម៉ាក្រូខុសពីអនុគមន៍ដូចម្ដេចដែរ?

14/   ចូរបង្កើតអនុគមន៍ដើម្បីដោះស្រាយប្រព័ន្ធសមីការពីរអញ្ញត្ដិខាងក្រោម ៖

ax by = c

dx ey = f

ក្នុងនោះ a, b, c, d, e, f គឺជាប៉ារ៉ាមែត្រដែលត្រូវបញ្ចូលតំលៃអោយវា។

 

 

 

= = = = = * = = = = =