Զրույցներ C ծրագրավորման լեզվի մասին

Զրույց իներորդ

Այս զրույցը 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;
}

Վարժություն

  1. Գրել թեստերի խումբ, որն ամբողջությամբ ստուգում է այս վերջին ծրագիրը։