Այս զրույցը C լեզվով գրված ծրագրերին հրամանային տողից փոխանցված արգումենտների մասին է։
Գործարկման պահին հրամանային տողում տրված արգումենտները ծրագրում հասանելի դարձնելու համար պետք է main
ֆունկցիան (ծրագրի մուտքի կետը) սահմանել int
և char**
տիպի պարամետրերով։
int main( int, char** );
Այդ պարամետրերից առաջինը, որին ավանդաբար ընդունված է տալ argc
(argument count - արգումենտների քանակ) անունը, ցույց է տալիս հրամանային տողի բաղադրիչների քանակը՝ ներառյալ ծրագիր անունը։ Օրինակ, եթե prog09a.c
ծրագիրը կոմպիլյացնելու համար հրամանային տողում գրում եմ.
clang prog09a.c -o prog09a
ապա clang
ծրագրի main
ֆունկցիայի առաջին (argc
) պարամետրը կստանա 4 արժեքը։
main
ֆունկցիայի երկրորդ պարամետրը, որ հայտարարվել է char**
տիպով, հրամանային տողի բաղադրիչների հասցեների զանգվածն է։ Քանի որ արգումենտները հրամանային տողից փոխանցվում են տեղերի տեսքով, իսկ տողի տիպը char*
է, ապա այդ տողերի հասցեների զանգվածի տիպը կլինի char**
։ Այս երկրորդ պարամետրին էլ ավանդաբար ընդունված է տալ argv
(argument values - արգումենտների արժեքներ) անունը։
Հրամանային տողից տրված արգումենտների օգտագործումը ցուցադրելու համար գրեմ մի ծրագիր, որը հերթականությամբ արտածում է հրամանային տողում տրված արգումենտները և դրանց ինդեքսները։
#include <stdio.h>
int main( int argc, char** argv )
{
for( int c = 0; c < argc; ++c )
printf( "%d: %s\n", c, argv[c] );
return 0;
}
Այս ծրագիրը պահպանում եմ prog09a.c
ֆայլում, կոմպիլյացնում եմ սովորականի պես և գործարկում եմ ահա այսպես․
$ ./prog08b abcd 123 'efgh 45'
Աշխատանքի արդյունքում ստանում եմ հետևյալ արտածումը, որից երևում է, որ argc
պարամետրը ստացել է 4 արժեքը, իսկ argv
ցանգվածի տարրերը ցույց են տալիս համապատասխանաբար ./prog09a
, abcd
, 123
և efgh 45
տողերին։
0: ./prog09a
1: abcd
2: 123
3: efgh 45
Այսքանը, թերևս, բավական է C լեզվով գրված ծրագրերում հրամանային տողից տրված արգումենտների հետ աշխատանքի մասին պատկերացում կազմելու համար։ Բայց ես ուզում եմ մի օրինակ էլ բերել, որտեղ բացի այն, որ ծրագիրն օգտագործում է հրամանային տողի արգումենտները, այլև դրանք օգտագործում է իր ճիշտ վարքը կազմակերպելու համար։
Ես գրում եմ մի ծրագիր, որը հրամանային տողի երկրորդ արգումենտով տրված տասական թիվը ձևափոխում է երկուական, ութական կամ տասնվեցական ներկայացման։ Ձևափոխման ֆորմատը տրվում է հրամանային տողի առաջին արգումենտով։
Ծրագրում օգտագործելու եմ ֆունկցիաներ, որոնք հայտարարված են ctype.h
, math.h
, stdio.h
և string.h
ֆայլերում։
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
Առաջին գործը պետք է լինի ստուգել, որ հրամանային տողում տրված են ճիշտ երկու արգումենտներ։ Քանի որ argc
պարամետրը հաշվում է նաև ծրագիր անունը, ապա այն պետք է համեմատել 3-ի հետ։
int main(int argc, char** argv)
{
/* Հրամանային տողում պետք է տալ անպայման երկու արգումենտ */
if( argc != 3 ) {
puts("Սպասվում է ճիշտ երկու արգումենտ։");
printf("%s <ֆորմատ> <թիվ>\n", argv[0]);
return 1;
}
Առաջին արգումենտի առաջին նիշը ցույց է տալիս նոր ներկայացման ֆորմատը։ Այն կարող է լինել «b
», «o
» կամ «h
»։ Ստուգում եմ նաև այդ պայմանը։
/* Թվի ֆորմատը ցույց տվող պարամետրը */
char format = argv[1][0];
/* Առաջին արգումենտը պետք է լինի «b» «o» կամ «h» */
if( 'b' != format && 'o' != format && 'h' != format ) {
puts("Սխալ ֆորմատի արգումենտ։ Պետք է լինի․");
puts(" b - երկուական,");
puts(" օ - ութական,");
puts(" հ - տասնվեցական։");
return 2;
}
Ձևափոխվող թիվը, որ տրված է երկրորդ արգումենտով, պետք է բաղկացած լինի միայն տասական թվանշաններից։
/* Երկրորդ արգումենտը պետք է բաղկացած լինի միայն թվանշաններից */
for( int i = 0; i < strlen(argv[2]); ++i )
if( !isdigit(argv[2][i]) ) {
puts("Թիվը պետք է բաղկացած լինի միայն տասական թվանշաններից։");
return 3;
}
Բոլոր ստուգումներն արդեն արված են։ Եթե ծրագիրը կհայտնաբերի սխալներ կան ոչ ճիշտ մուտքային տվյաներ, ապա դրանց մասին կտրվի համապատասխան հայտարարություն և ծրագրի աշխատանքը կավարտվի՝ օպերացիոն համակարգին վերադարձնելով համապատասխան սխալի կոդ։
Հրամանային տողից ձևափոխվող թիվը ծրագրին հասանելի է տողի տեսքով։ Որպեսզի նրա հետ հնարավոր լինի աշխատել որպես թիվ, scanf
ֆունկցիայով argv[2]
տողից ստանում եմ int
արժեք։
/* Ձևափոխվելիք տասական թիվը */
int dec_number = 0;
sscanf(argv[2], "%d", &dec_number);
Հիմա բուն ձևափոխությունները։ C լեզվի printf
ֆունկցիան կարողանում է տասական թիվը ձևափոխել ութական և տասնվեցական տեսքերի․ պետք է պարզապես օգտագործել համապատասխանաբար %o
և %x
ֆորմատավորման հրահանգները։
if( 'o' == format )
printf("0%o\n", dec_number);
else if( 'h' == format )
printf("0x%x\n", dec_number);
Բայց թվի երկուական տեսքը ստանալու համար պետք է մի քիչ աշխատել։ Հայտնի է, որ թվի տասական ներկայացումից երկուական ներկայացումը ստանալու համար պետք է հակառակ կարգով վերցնել նրա՝ երկուսին բաժանելուց ստացված մնացորդները։ Եվ որպեսզի այդ մնացորդները գրեմ ճիշտ հաջորդականությամբ՝ աջից ձախ, պետք է իմանամ, թե թվի երկուական ներկայացման համար քանի դիրք է հարկավոր։ Այդ նիշերի քանակը ստանալու համար պետք վերցնել տասական թվի երկու հիմքով լոգարիթմը։ Դրանից հետո պարզապես պետք է dec_number
թիվը բաժանել երկուսի այնքան անգամ, քանի դեռ այն չի հավասարվել զրոյի։
else if( 'b' == format ) {
/* Թվի երկուական նիշերի քանակը */
int nc = log(dec_number)/log(2.0);
/* Ձևափոխված թվի բուֆեր */
char str_number[32] = { 0 };
/* Ձևափոխություն երկուական տեսքի */
while( dec_number != 0 ) {
str_number[nc] = '0' + dec_number % 2;
dec_number /= 2;
--nc;
}
/* Արդյունքի արտածում */
printf("%s\n", str_number);
}
return 0;
}
Վարժություն