Česky
Kamil Dudka

Tiny programs (C, C++, C#, ...)

File detail

Name:Downloadproj1.c [Download]
Detected charset:ISO-8859-2 - [Download as UTF-8]
Location: tiny > IZP > proj1
Size:8.3 KB
Last modification:2009-12-21 17:54

Source code

/*
 * Soubor:  proj1.c
 * Datum:   9.11.2004
 * Autor:   Kamil Dudka, xdudka00@stud.fit.vutbr.cz
 *
 * Prosím, neodevzdávejte zdrojové kódy, které jsou zde k dispozici,
 * jako Vaše školní projekty. Děkuji :-)
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define DELKA 33  // Staci pro nacteni cisla ULONG_MAX ve dvojkove soustave (retezec je ukoncen nulou)
#define CHYBA_VSTUPU 64  // Musi byt vzdy vetsi nez zaklad soustavy
#define CHYBA_PRETECENI 128  // Musi byt vzdy vetsi nez zaklad soustavy
 
  // Prototypy pouzitych funkci
unsigned int ctiVSoustave (char *, unsigned int, unsigned int);
int doDesitkove (unsigned long *, char *, unsigned int);
int zDesitkove (char *, unsigned long, unsigned int, unsigned int);
unsigned char cisloZCifry (unsigned char);
unsigned char cifraZCisla (unsigned char);
void otocRetezec (char *);
 
  // Hlavni program
int main (int argc, char *argv[])
{
  unsigned long zakladVstup;
  unsigned long zakladVystup;
 
  unsigned long desitkovaSoustava;
  char jinaSoustava [DELKA];
 
  unsigned int kodChyby = EXIT_SUCCESS;  // nebyla zjistena zadna chyba
 
    // Osetreni poctu vstupnich parametru
  if (argc<3)
  {  // Pokud je zadano mene nez dva parametry vypise se help - vyhnu se tim zbytecnym chybam a splnuje to zadani !!!
  printf("Program císelné soustavy.\n"
         "Autor: Kamil Dudka\n"
         "Program provádí prevody mezi císelnými soustavami. císlo, které\n"
         "má program zpracovat se nacítá ze standardního vstupu.\n"
         "Pou?ití: proj1 -h\n"
         "         proj1 Z1 Z2\n"
         "Popis parametr?:\n"
         "  -h    Vypíse tuto obrazovku s nápov?dou.\n"
         "  Z1    Základ císelné soustavy vstupního císla (2-36).\n"
         "  Z2    Základ císelné soustavy výstupního císla (2-36).\n"
         );
    return EXIT_FAILURE;
  }
  if (argc>3)
  {
    fprintf (stderr,"Prilis mnoho parametru!\n");
    return EXIT_FAILURE;
  }
 
    // Ostereni prvniho parametru
  if (0 != doDesitkove (&zakladVstup, argv[1], 10))  // Prevod retezce na cislo - vyuzivam stejny podprogram jako pro prevod
  {
    fprintf (stderr,"Neplatny parametr 1!\n");
    kodChyby = EXIT_FAILURE;
  }
  else if ((zakladVstup<2)|(zakladVstup>36))
  {
    fprintf (stderr,"Neplatny zaklad ciselne soustavy pro vstupni hodnotu\n");
    kodChyby = EXIT_FAILURE;
  }
 
    // Ostereni druheho parametru
  if (0 != doDesitkove (&zakladVystup, argv[2], 10))  // Prevod retezce na cislo - vyuzivam stejny podprogram jako pro prevod
  {
    fprintf (stderr,"Neplatny parametr 2!\n");
    kodChyby = EXIT_FAILURE;
  }
  else if ((zakladVystup<2)|(zakladVystup>36))
  {
    fprintf (stderr,"Neplatny zaklad ciselne soustavy pro vystupni hodnotu\n");
    kodChyby = EXIT_FAILURE;
  }
 
    // Pokud byla zjistena nejaka chyba, program skonci
  if (kodChyby == EXIT_FAILURE)
    return EXIT_FAILURE;
 
    // Nacteni vstupniho cisla
  if (0==ctiVSoustave (jinaSoustava, DELKA, zakladVstup))
  {
    fprintf(stderr,"Chyba vstupu\n");
    return EXIT_FAILURE;
  }
 
    // Prevod cisla do desitkove soustavy
  kodChyby = doDesitkove (&desitkovaSoustava, jinaSoustava, zakladVstup);
  if (kodChyby != 0)
  {  // behem prevodu doslo k chybe
 
    if (kodChyby==CHYBA_VSTUPU)
      fprintf(stderr,"Chyba vstupu!\n");
    if (kodChyby==CHYBA_PRETECENI)
      fprintf(stderr,"Chyba preteceni\n");
    return EXIT_FAILURE;
  }
 
    // Prevod cisla z desitkove soustavy
  if (0!= zDesitkove (jinaSoustava, desitkovaSoustava, zakladVystup, DELKA))
  {  // behem prevodu doslo k chybe
 
    fprintf (stderr,"Chyba preteceni!\n");
    return EXIT_FAILURE;
  }
  printf ("%s\n",jinaSoustava);
 
  return EXIT_SUCCESS;  // K zadne chybe nedoslo
}
 
    // Cteni vstupniho cisla v dane soustave - vraci pocet nactenych znaku
unsigned int ctiVSoustave (char *jinaSoustava, unsigned int delka, unsigned int zaklad)
{
  int znak;  // pro znak je zvolen typ int aby bylo mozno detekovat znak EOF
  unsigned int i=0; // inkrementacni promennou budu potrebovat i vne cyklu FOR
 
    // cylkus nacte cislo po jednom znaku a u kazdeho kontroluje jestli je platny pro danou soustavu
  while (i<delka-1)
  {
    znak = getchar ();
 
      // ukonceni cyklu
    if ((znak=='\n')|(znak==EOF))
      break;
 
      // kontrola znaku
    if (cisloZCifry ((char) znak) >= zaklad)  // hodnota CHBYBA_VSTUPU musi byt samozrejme taky vetsi nez zaklad  - tim usetrim jednu podminku
      return 0;
 
      // vlastni zapis znaku do pameti a inkrementace ukazatele
    jinaSoustava[i]=znak;
    i++;
  }
 
    // zakonceni retezce nulou (kontroluji velikost zasobniku predanou parametrem "delka")
  if (delka>0)
    jinaSoustava[i] = 0;
  return i;
}
 
  // Prevod do desitkove soustavy
int doDesitkove (unsigned long *vystup, char *vstup, unsigned int zaklad)
{
    // inicializace promennych
  unsigned long stradac;
  unsigned long nasobitel = 1;  // Zacnu od cifry z nejnizsi hodnotou, tj. Z na nultou je vzdy 1
  unsigned long proKontrolu = 0;  // pomocna promenna pro kontrolu preteceni jednotlivyc operaci
  int nasobitelPretekl = 0;
 
  *vystup = 0;
 
    // Hlavni cyklus prevodu - zacinam od cifry z nejnizsi hodnotou
  for (int i = strlen (vstup) - 1; i >= 0; i--)
  {
      // kontrola preteceni nasobitele
    if (nasobitel/zaklad != proKontrolu)
      nasobitelPretekl = 1;
 
      // nacteni hodnoty aktualni cifry
    if ((proKontrolu = stradac = cisloZCifry (vstup[i]))!=0)
    {  // pokud je aktualni cifra rovna nule, tak nemusim resp. nemuzu spoustu veci vubec testovat
 
         // kontrola preteceni nasobitele z predchoziho kroku - tim umoznim zpracovani cisla pred kterym je hodne nul
      if (nasobitelPretekl)
        return CHYBA_PRETECENI;
 
        // Neplata vstupni data - cyklus se okamzite ukonci
      if ((stradac == CHYBA_VSTUPU)|(stradac >= zaklad))
        return CHYBA_VSTUPU;
 
        // kontroluji jestli neni cislo stradac*nasobitel mimo rozsah unsigned long
      stradac *= nasobitel;
      if (stradac/proKontrolu != nasobitel)
        return CHYBA_PRETECENI;
    }
 
      // hodnotu cisla *vystup z predchoziho kroku si ulozim do promenne
    proKontrolu = *vystup;
 
      // kontorluji preteceni vystupni promenne
    *vystup += stradac;
    if (*vystup < proKontrolu)
      return CHYBA_PRETECENI;
 
    proKontrolu = nasobitel;
    nasobitel *= zaklad;  // Z kazdou dalsi cifrou zvysim mocninu zakladu (nasobitel)
  }
  return EXIT_SUCCESS;
}
 
  // Funkce vraci cislo, ktere cifra predstavuje, pro neplatnou cifru vraci hodnotu CHYBA_VSTUPU
unsigned char cisloZCifry (unsigned char cifra)
{
  if (cifra<'0')
    return CHYBA_VSTUPU;
 
    // cislo
  if (cifra<='9')
    return cifra-'0';
 
  if (cifra<'A')
    return CHYBA_VSTUPU;
 
    // velke pismeno
  if (cifra<='Z')
    return cifra-'A'+10;
 
  if (cifra<'a')
    return CHYBA_VSTUPU;
 
    // male pismeno
  if (cifra<='z')
    return cifra-'a'+10;
 
  return CHYBA_VSTUPU;
}
 
  // Funkce prevadi cislo z desitkove soustavy
int zDesitkove (char *vystup, unsigned long vstup, unsigned int zaklad, unsigned int delka)
{
  unsigned int i=0;  // Inkrementacni promenna - budu ji pouzivat i mimo cyklus
  do {
      // kontrola rozsahu pole pro vystupni data (jeden znak si rezervuji jako ukoncovaci)
    if (i<delka-1)
    {
      vystup[i] = cifraZCisla (vstup % zaklad);  // zbytek po deleni zakladem prevedu o5 na znak a ulizim do danne cifry
      vstup /= zaklad;
    }
    else
    {  // vysledek je neplatny - cyklus skonci
 
      vystup[i] = 0;
      return CHYBA_PRETECENI;
    }
    i++;
  } while (vstup>0);
 
  vystup[i]=0;  // vznikly retezec zakonci nulou
  otocRetezec (vystup);  // pro spravne zobrazeni cisla je treba retezec otocit
  return EXIT_SUCCESS;
}
 
  // Funkce vraci znak odpovidajicimu zadanemu cislu
unsigned char cifraZCisla (unsigned char cislo)
{
    // pro hodnotu >35 funkce vraci nulu - k tomu prakticky nikdy nedojde
  if (cislo>35)
    return 0;
 
    // provede vypocet podle toho jestli se jedna o cislici nebo pismenko
  if (cislo>9)
    return cislo+'A'-10;
  else
    return cislo+'0';
}
 
  // Funkce otaci retezec dany ukazatelem - funkce neni zadnym zpusobem optimalizovana !!!
void otocRetezec (char *retezec)
{
  unsigned int delka = strlen(retezec);  // Delku retezce zjistuje jen jednou a to na zacatku funkce
  unsigned int i;
 
  for (i=0; i<(delka/2); i++)  // cyklus se provede jen s polovicnim poctem cyklu nez je delka retezce
  {
      // vlastni vymena dvou prvku
    retezec[i] ^= retezec[delka-i-1];
    retezec[delka-i-1] ^= retezec[i];
    retezec[i] ^= retezec[delka-i-1];
  }
}