Նախորդ զրույցներում իմ բերած օրինակները շատ պարզ էին․ ծրագիրը սկսվում էր main
ֆունկցիայից, կանչվում էր այս կամ այն ֆունկցիան, կատարվում էին հաջորդական գործողություններ ու ծրագրի կատարումն ավարտվում էր։ Իսկ ի՞նչ անել, երբ պետք է ծրագրի տրամաբանությունը ղեկավարել ներմուծված կամ ձևավորված տվյալներից կախված։ Օրինակ, ինչպե՞ս սահմանեմ թվի նշանը որոշող sign
ֆունկցիան։ Այն պետք է արգումենտում ստացած դրականների թվի համար վերադարձնի՝ 1
, բացասականի համար՝ -1
, իսկ զրոյի համար՝ 0
։ Պարզ է, որ ֆունկցիայի այդպիսի վարքը մոդելավորելու համար հարկավոր է ճյուղավորման հրաման։
C լեզվում ճյուղավորումները կազմակերպվում են if
հրամանով.
if( ⟨condition⟩ ) ⟨then-block⟩ else ⟨else-block⟩
Եթե ճշմարիտ է ⟨condition⟩
պայմանը, ապա կատարվում են ⟨then-block⟩
հրամանները, հակառակ դեպքում կատարվում են ⟨else-block⟩
հրամանները։ Եթե պայմանի կեղծ լինելու դեպքում ոչինչ անել պետք չէ, ապա else
ծառայողական բառը և նրան հաջորդող ⟨else-block⟩
հրամանները կարելի է չգրել։ Օրինակ, այսպես.
if( argc == 1 )
usage();
usage
ֆունկցիան կանչվում է միայն այն դեպքում, երբ argc
փոփոխականը հավասար է մեկի։
Արդեն տեղին է հիշատակել C լեզվի համեմատման գործողությունների մասին։ Դրանք վեցն են և նախատեսված են թվերի ու նիշերի համեմատման համար, իսկ ==
և !=
գործողությունները օգտագործվում են նաև ցուցիչների հավասարությունն ու անհավասարությունը ստուգելու համար։
Գործողություն | Նշանակություն |
---|---|
== |
հավասար է |
!= |
հավասար չէ |
> |
մեծ է |
>= |
մեծ է կամ հավասար |
< |
փոքր է |
<= |
փոքր է կամ հավասար |
Հիմա վերը հիշատակված sign
ֆունկցիայի մասին։ Այն կարող է ունենալ հետևյալ տեսքը.
int sign( double num )
{
int res = 0; /* զրոյի դեպքը */
if( num < 0 ) /* եթե բացասական է */
res = -1;
else if( num > 0 ) /* այլապես եթե դրական է */
res = 1;
return res;
}
Բայց, քանի որ return
հրամանն իր կիրառման կետում ավարտում է ֆունկցայի աշխատանքը, sign
ֆունկցիան կարելի է գրել ավելի պարզ ձևով։
int sign( double num )
{
if( num < 0 ) return -1; /* բացասական */
if( num > 0 ) return 1; /* դրական */
return 0; /* զրո */
}
Ճյուղավորման հրամանը հնարավորություն է տալիս ծրագրում կազմակերպել նաև կրկնություններ։ Օրինակ, տրված x
թվի y
աստիճանը (երկուսն էլ ամբողջ թվեր են) հաշվող ֆունկցիան կարող եմ սահմանել հետևյալ կերպ.
int power( int x, int y )
{
if( y == 0 ) /* թվի զրո աստիճանը */
return 1; /* 1 է */
return x * power( x, y - 1 ); /* x^y = x * x^(y - 1) */
}
Այս ֆունկցիայում կրկնությունը մոդելավորված է ռեկուրսիայի օգնությամբ. x
թվի հերթական y
աստիճանը հաշվելու համար x
-ը բազմապատկվում է իր y-1
աստիճանի արժեքի հետ։ Եթե որպես աստիճան տրված է 0
, ապա վերադարձնում է 1
։
Մեկ այլ օրինակ՝ առանց ռեկուրսիայի օգտագործման։ powers_of_two
ֆունկցիան արգումենտում ստանում է N
ամբողջ թիվը և ստանդարտ արտածման հոսքին է արտածում 2
-ի [0..N]
աստիճանների աղյուսակը.
void powers_of_two( int nm )
{
int pw = 0;
cycle:
printf( "2^%d = %d\n", pw, 1 << pw );
pw = pw + 1;
if( pw <= nm ) goto cycle;
}
Այստեղ ցիկլի կազմակերպման համար ես օգտագործել եմ goto
հրամանը և մի նշիչ (label)։ C լեզվի նշիչները իդենտիֆիկատորներ են, որոնցից հետո դրվում է :
։ Դրանք կարող են գրվել ցանկացած հրամանից առաջ և օգտագործում են այդ հրամանին ուղղակի անցում կատարելու համար։ powers_of_two
ֆունկցիայի չորրորդ տողում գրված է cycle
նշիչը, որին յոթերորդ տողում գրված goto
հրամանով անցում է կատարվում այն դեպքում, երբ pw
-ի արժեքը դեռևս փոքր է nm
-ի արժեքից։
Երկուսի հերթական pw
աստիճանը հաշվարկվում է 1 << pw
արտահայտությամբ (printf
ֆունկցիայի երրորդ արգումենտում)։ Այս <<
գործողությունը իր ձախ արգումենտի բիթերը դեպի ձախ է տեղաշարժում աջ արգումենում տրված քանակով՝ ազատված դիրքերը լրացնելով զրոներով։
Բացի if-else
ճյուղավորման հրամանից, C լեզուն ունի նաև switch
ընտրության հրամանը, որը թույլ է տալիս ընտրություն կատարել արտահայտության արժեքներ մեջ և ամեն մի արժեքին համապատասխանեցնել հրամանների առանձին հաջորդականություն։ Նրա ընդհանուր տեսքն այսպիսինն է.
switch( ⟨expression⟩ ) {
case ⟨value_1⟩:
⟨block_1⟩
case ⟨value_2⟩:
⟨block_2⟩
...
default:
⟨block_!⟩
}
switch
հրամանի արգումենտի ⟨expression⟩
արտահայտությունը պետք է լինի ամբողջաթիվ կամ նիշային, իսկ case
հրամանի արգումենտները՝ նույն տիպի հաստատուններ։ Եթե ⟨expression⟩
-ի արժեքը ⟨value_1⟩
է, ապա կատարվում են ⟨block_1⟩
խմբի հրամանները, եթե ⟨value_2⟩
է, ապա՝ ⟨block_2⟩
հրամանները և այդպես շարունակ։ Եթե ⟨expression⟩
-ի արժեքը ոչ մի case
տարբերակի չի համընկնում, ապա կատարվում է default
ծառայողական բառից հետո գրված ⟨block_!⟩
հրամանները։
Օրինակ, սահմանեմ day_of_week
(շաբաթվա օր) ֆունկցիան, որն արգումենտում ստանում է ամբողջ թիվ և արտածում է համապատասխան շաբաթվա օրվա անունը։
void day_of_week( int day )
{
switch( day ) {
case 1:
puts( "երկուշաբթի" );
break;
case 2:
puts( "երեքշաբթի" );
break;
case 3:
puts( "չորեքշաբթի" );
break;
case 4:
puts( "հինգշաբթի" );
break;
case 5:
puts( "ուրբաթ" );
break;
case 6:
puts( "շաբաթ" );
break;
case 7:
puts( "կիրակի" );
break;
default:
puts( "այդպիսի համարով օր չկա" );
}
}
Պետք է ուշադրություն դարձնել, որ բոլոր case
բլոկներն ավարտվում են break
հրամանով։ Բանն այն է, որ switch
հրամանի մարմինը հրամանների մի ընդհանուր հաջորդականություն է, իսկ case
և default
հրամաններն այդ հաջորդականության մեջ ձևավորում են նշիչներ։ Երբ սկսվում է կատարվել բլոկներից որևէ մեկը, ապա կատարվում են switch
հրամանի մարմնի հաջորդ բոլոր հրամանները։ break
հրամանը հնարավորություն է տալիս կատարումն ընդհատել հարկավոր տեղում։
Օրինակ, սահմանեմ working_day
(աշխատանքային օր) ֆունկցիան, որը [1..5]
օրերի համար արտածում է «աշխատանքային օր է» արտահայտությունը, իսկ 6
և 7
օրերի համար՝ «հանգստյան օր է» արտահայտությունը։
void working_day( int day )
{
switch( day ) {
case 1:
case 2:
case 3:
case 4:
case 5:
puts( "աշխատանքային օր է" );
break;
case 6:
case 7:
puts( "հանգստյան օր է" );
break;
default:
puts( "այդպիսի համարով օր չկա" );
}
}
Հետաքրքրության համար կարելի է հեռացնել break
հրամանները և տեսնել, թե ինչ կկատարվի։
day_of_week
ֆունկցիան սահմանեմ նաև if-else
հրամանի օգնությամբ.
void day_of_week( int day )
{
if( day == 1 )
puts( "երկուշաբթի" );
else if( day == 2 )
puts( "երեքշաբթի" );
else if( day == 3 )
puts( "չորեքշաբթի" );
else if( day == 4 )
puts( "հինգշաբթի" );
else if( day == 5 )
puts( "ուրբաթ" );
else if( day == 6 )
puts( "շաբաթ" );
else if( day == 7 )
puts( "կիրակի" );
else
puts( "այդպիսի համարով օր չկա" );
}
Հերթով դիտարկվում են day
արգումենտի արժեքները և ամեն մեկի համար արտածվում է համապատասխան բառը։ Ամենավերջին else
ճյուղը կատարվում է այն դեպքում, երբ day
փոփոխականի արժեքը [1..7]
միջակայքից չէ։