Elektroda.pl
Elektroda.pl
X
Elektroda.pl
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

C - problemy z zamianą liczb z arabskich na rzymskie i odwr.

17 Lis 2008 10:10 11601 35
  • Poziom 11  
    Witam, problem zamiany liczb w systemach arabskim i rzymskim widzę następująco: Zapisanie wpisanej z klawiatury liczby do jednowymiarowej tablicy, po jednym znaku na komórkę. To ułatwi (przynajmniej według mnie) rozpoznanie systemu, w jakim zapisana jest liczba. W zależności od systemu zaprzęgnięta będzie funkcja zamiany z tego systemu na inny. Wynik może być od razu wypisany na ekran.
    Mam juz napisany kawałek tego programu, ale nie mogę przeskoczyć jednej rzeczy. Jak zmusić program, by wczytywał znaki z klawiatury do tablicy, podczas kiedy w ogóle jakieś są? Wpisanie liczby będzie zakończone zatwierdzeniem enterem.

    Czy może ma ktoś jakąś propozycję, np zrezygnowania z tablicy, ale wtedy nasuną mi sie kolejne pytania.
  • VIP Zasłużony dla elektroda
    Code:
    #include <stdio.h>
    
    char tablica[80];
    scanf("%79s ", tablica);


    Pozdrawiam,
    Dr.Vee
  • Poziom 20  
    Ja tak zamieniam liczby rzymskie (w zakresie od 1 do 3999) na dziesiętne - program w Pascalu. Jeśli z tego skorzystasz, to chętnie zobaczę Twój program w C.

    Code:

    program liczby_rzymskie;
    var n: word; rzym: string;
    begin
    write('n = '); readln(n);
    rzym:='';

    while n >= 1000 do begin n:=n-1000; rzym:=rzym+'M' end;
    if n >= 900 then begin n:=n-900; rzym:=rzym+'CM' end;
    if n >= 500 then begin n:=n-500; rzym:=rzym+'D' end;
    if n >= 400 then begin n:=n-400; rzym:=rzym+'CD' end;

    while n >= 100 do begin n:=n-100; rzym:=rzym+'C' end;
    if n >= 90 then begin n:=n-90; rzym:=rzym+'XC' end;
    if n >= 50 then begin n:=n-50; rzym:=rzym+'L' end;
    if n >= 40 then begin n:=n-40; rzym:=rzym+'XL' end;

    while n >= 10 do begin n:=n-10; rzym:=rzym+'X' end;
    if n >= 9 then begin n:=n-9; rzym:=rzym+'IX' end;
    if n >= 5 then begin n:=n-5; rzym:=rzym+'V' end;
    if n >= 4 then begin n:=n-4; rzym:=rzym+'IV' end;

    while n > 0 do begin n:=n-1; rzym:=rzym+'I' end;
    writeln(rzym);
    write('Naciśnij Enter...');
    readln
    end.
  • Poziom 25  
    Dr.Vee napisał:
    Code:
    #include <stdio.h>
    
    char tablica[80];
    scanf("%79s ", tablica);


    Wydaje mi sie ze to nie zadziala za dobrze jesli ktos poda w danych spacje. Czesc danych zostanie odrzucona. Proponowal bym zajac sie funkcja gets.
  • Poziom 11  
    Dr.Vee, Czy mógłbyś objaśnić jak działa to co jest w Twoim kodzie?
    Czy to zapisuje osobne znaki w osobnych komórkach?

    Potrzebuję też, aby tablica była zapełniona od którejś strony, wygodniej pewnie od prawej (ostatni znak w ostatniej komórce), ewentualnie sobie ją przepiszę ale musze wiedzieć ile znaków wczytał, może jakaś pętla do while?
    O ile przy zamianie z rzymskiego dużo to nie da, to z arabskiego już coś da. Albo jak można przejechac po tablicy aby zobaczyć, że już nic w niej nie ma?
  • VIP Zasłużony dla elektroda
    one_eddie napisał:
    Proponowal bym zajac sie funkcja gets.
    Na Twoim miejscu powstrzymałbym się przed udzielaniem tego typu "porad". Przy użyciu tej funkcji nie ma żadnej możliwości kontrolowania rozmiaru wczytywanego napisu, co prowadzi do katastroficznych błędów przepełnienie bufora. Jeśli ktoś musi wczytywać całe linie, to używa fgets().

    padalec007 napisał:
    Czy mógłbyś objaśnić jak działa to co jest w Twoim kodzie?

    Jak działa? Funkcja scanf pomija białe znaki na początku wejścia (nie dla każdej konwersji -> RTFM), wczytuje do 79 znaków nie-białych (!isspace(c)), zakańcza napis znakiem '\0'. Ilość wczytanych znaków sprawdzasz poprzez strlen(tablica), albo ewentualnie stosujesz konwersję %n - demo poniżej.
    Code:
    #include <stdio.h>
    
    #include <string.h>

    int main(void) {
        int i1,i2;
        char tab[80];

        scanf(" %n%79s%n", &i1, tab, &i2);
        printf("Wczytano %d bialych znakow, napis '%s', dlugosc napisu: %d (%d-%d=%d)\n",
                i1, tab, strlen(tab), i2, i1, i2-i1);
        return 0;
    }

    Oczywiście można też wczytać całą linię za pomocą fgets() i przetwarzać znaki albo w pętli, albo np. sscanf(), jak komu wygodniej. Można też zmusić funkcję scanf, żeby akceptowała tylko cyfry arabskie/rzymskie, np:
    Code:
    scanf(" %79[0-9]", tab);
    
    scanf(" %79[ivxlcdmIVXLCDM]", tab);
    Polecam lekturę manuala, za pomocą funkcji scanf można rozwiązać dużo problemów na raz ;)

    Pozdrawiam,
    Dr.Vee
  • Poziom 25  
    @Dr...: Proponowal bym wyrobic w sobie wiecej dystansu do siebie. Rada byla sluszna. Gdyby ta funkcja byla tak straszna jak to bylo sugerowana nie byla by udostepniona. Ma pewne mankamenty ktorych trzeba byc swiadom, ale tak jest ze wszystkim czego uzywamy.

    Skanowanie strumienia to bardzo dobra technika ale nie sprawdza sie we wszystkich przypadkach. osobiscie uwazam ze tutaj nalezalo byc uzyc funkcji fgetc wraz z isdigit/isalpha i znak po znaku sprawdzac poprawnosc wprowadzanych danych.

    Jesli zaznaczenie slowa "porada" oznaczalo ze napisalem cos zle prosze wskazac bledna wypowiedz, jesli nie prosze sie powstrzymac od wyglaszania nieprawdziwych tez.

    Zauwazony przezemnie kod ma jeszcze inna wade. Magic values to cos czego nie powinno sie robic, a jak widac mozna. Rozmiaru buforow powinny miec swoje uzasadnienie nie bierzemy zalozec z kosmosu lub innego podobnie nieznanego miejsca, a tak wlasnie zostalo zrobione.

    Dodano po 5 [minuty]:

    Maly fragment prezentujacy to o czym mowilem:

    Code:
    puts("Enter your data: ");
    
    const int max_numer_length = 15; // magic number!
    char num[max_numer_length];
    fgets(num, max_numer_length, stdin);


    Dodano po 4 [minuty]:

    Ciekawsze podejscie:

    Code:
    puts("Enter your data: ");
    
    int input_length = 0;
    const int max_numer_length = 15; // magic number!
    char num[max_numer_length] = { 0 };
    while (input_length < max_numer_length)
    {
       int c = fgetc(stdin);
       if (isdigit(c))
       {
          num[input_length++] = c;
       }
       //else print error message
    }


    Kod jest oczywiscie z drobnym bledem. Nalezalo by tu jeszcze zadbac o znak \0 na koncu bufora jesli zamierzamy bgo wyswietlic oraz zmniejszenie ilosci pobieranych danych aby ten znak pomiescic.
  • Poziom 11  
    Ok, program już wczytuje pięknie tablicę znaków, ale mam jeden problem, chcę, aby po zakończeniu program "pytał" czy chce wpisac nastepną liczbe i zeby zeskanował cos typu T/N i jeśli T to żeby odpalił się jeszcze raz. Mógłbym wsadzić zawartosć main w pętlę do while. Z tym, że jest jeden problem, po wykonaniu się programu, czyli w efekcie po jednym wczytaniu z klawiatury, wypluwa wynik, ewentualnie dowolną ilośc rzeczy może wydrukować, ale nic więcej nie chce już wczytać, nie wiem w czym rzecz, czy on może tylko jeden raz wczytać coś? Jeśli nawet przeskoczę koniecznosc wczytania T ustalając przed pętlą, że zawsze T, to program odpala się do drugi raz, czyli raz zapyta i wypluje wynik, drugi raz wypluwa poprzedni wynik i dopiero pyta. Czemu?
  • VIP Zasłużony dla elektroda
    one_eddie napisał:
    Gdyby ta funkcja byla tak straszna jak to bylo sugerowana nie byla by udostepniona. Ma pewne mankamenty ktorych trzeba byc swiadom, ale tak jest ze wszystkim czego uzywamy.

    Funkcja jest udostępniona (i nie można jej usunąć), ponieważ znajduje się w standardzie ANSI C, który powstał dawno temu. Dzisiaj już wiadomo, że większość problemów z bezpieczeństwem programów wiąże się z błędami typu przepełnienie bufora.
    W standardzie znajduje się również kilka innych funkcji które mają poważne ograniczenia, ale funkcja gets() jest o tyle specyficzna, że przed jej ograniczeniami nie sposób się zabezpieczyć - program nie ma i nie może mieć kontroli nad tym, co otrzymuje na wejściu.

    one_eddie napisał:
    użyć fgetc wraz z isdigit/isalpha i znak po znaku sprawdzac poprawnosc wprowadzanych danych.

    Można, każdy użyje tego co mu bardziej pasuje.

    one_eddie napisał:
    Jesli zaznaczenie slowa "porada" oznaczalo ze napisalem cos zle prosze wskazac bledna wypowiedz, jesli nie prosze sie powstrzymac od wyglaszania nieprawdziwych tez.

    Nie bierz tego do siebie, ale rekomendowanie komuś funkcji gets() jest błędem z w/w powodów. A zwłaszcza początkującemu, na dodatek bez podkreślenia dlaczego funkcji tej nie należy używać.

    one_eddie napisał:
    Zauwazony przezemnie kod ma jeszcze inna wade. Magic values to cos czego nie powinno sie robic, a jak widac mozna. Rozmiaru buforow powinny miec swoje uzasadnienie nie bierzemy zalozec z kosmosu lub innego podobnie nieznanego miejsca, a tak wlasnie zostalo zrobione.

    Niestety krótkie i proste programy w C mają to do siebie, że gdy doda się do nich prawidłową obsługę pamięci, to przestają być krótkie i proste.

    Co do "magic values" to zgoda, dość trudno ich uniknąć przy poprawnym użyciu funkcji typu scanf(), gdzie muszą zostać wpisane do napisu formatującego. Można konstruować napis formatu dynamicznie, ale to generuje kolejne problemy.

    Natomiast Twoje przykłady ze stałymi nie są poprawne - w ANSI C (inaczej niż w C++ lub C99) rozmiar deklarowanej tablicy musi być wyrażeniem stałym znanym w czasie kompilacji, a zmienna z kwalifikatorem const nie jest takim wyrażeniem. Musiałbyś użyć #define rozmiar 15 albo ew. enum {rozmiar = 15};

    PS. padalec007 -> bez obejrzenia kodu Twojego programu można jedynie zgadywać...

    Pozdrawiam,
    Dr.Vee
  • Poziom 11  
    Dr.Vee napisał:
    bez obejrzenia kodu Twojego programu można jedynie zgadywać...

    Szkoda, miałem nadzieję, że to proste błędy, które kiedyś każdy popełniał i wie o co chodzi, ale jeśli bez tego się nie obędzie... szkoda, a więc oto kod który działa:
    Code:

    int main (void){
       int d;
        char liczba[79];
        char wynik[79];
        char czy_dalej;
        int rodzaj;
           printf("Podaj liczbe w systemie arabskim lub rzymskim.\n\n");
            scanf("%79s", liczba);
                          d=strlen(liczba);
            rodzaj=rozpoznawacz(liczba,d);
            if (rodzaj==0)
            wynik=zAdoR(liczba);
            else if (rodzaj==1)
            wynik=zRdoA(liczba);
                 else printf("Blad przy wpisaniu liczby.\n\n");
           
        system("PAUSE");
    }

    rozpoznawacz to funkcja która wypluwa 0 jako że liczba była w systemie arabskim - trzeba zrobić na rzymski, 1 jest rzymski - trzeba na arabski i 2 jako śmieć - czyli coś co nie jest żadnym systemem.
    Jeżeli przed system pause wpiszę printf(coś); to ładnie się wypisze, jeśli napiszę scanf(coś); to program to olewa i pisze "Aby zakończyć..."

    No i jeśli włożę to w pętlę to o ile zadziała to zadziała źle.
  • VIP Zasłużony dla elektroda
    Miałeś przeczytać manual do scanf(), link podawałem w poście powyżej... Eh lenistwo, lenistwo... ;)

    Scanf przestaje czytać wejście po napotkaniu pierwszego znaku, który "nie pasuje" do konwersji. W przypadku wywołania
    Code:
    scanf("%79s", liczba);
    konwersja kończy się po napotkaniu pierwszego białego znaku - czyli najprawdopodobniej znaku nowej linii. Ten znak pozostaje w buforze stdin.

    Wywołując następnie
    Code:
    scanf("%c", &czy_dalej);
    scanf wczyta właśnie ten znak nowego wiersza. Manual wyraźnie podaje, że przy konwersjach %c i %[ funkcja NIE pomija białych znaków przed konwersją. Żeby zmusić scanf do pominięcia białych znaków należy przed konwersją umieścić biały znak, np. spację. Dlatego
    Code:
    scanf(" %c", &czy_dalej);
    wykona to, o co Ci chodzi.

    Pozdrawiam,
    Dr.Vee
  • Poziom 11  
    Ach no teraz wszystko jest jasne, rzeczywiscie nie przeczytałem manuala, ale nie z lenistwa, a dlatego, że nie zauważyłem linku :D. Mimo wszystko przeczytam go, żeby wiedzieć więcej.
  • Poziom 11  
    Witam, mam problem z zamianą liczby zapisanej w tablicy char'ów na liczbę typu long int. Ja to widziałem tak:
    Code:
    long int arabska=0;
    
         int i;
             for (i=0;i<a;i++){
                 arabska+=t[i]*10e(a-(i+1));
             }
    a to dlugosc tablicy t[] w ktorej są znaki. Jednak coś mi się wydaje, że to nie działa, albo nie działa poprawnie, kompilator wyrzuca : exponent has no digits.
    Co z tym zrobic?
  • VIP Zasłużony dla elektroda
    Notacja LICZBAeLICZBA działa tylko dla stałych, czyli poprawnie jest 10e-3, ale nie 10e(-n).

    Możesz wykorzystać funkcję
    Code:
    #include <math.h>
    
    double pow(double x, double y);
    Chyba i tak łatwiej będzie zapamiętywać kolejną potęgę, np.
    Code:
    int potega = 1, i = 0;
    
    for (i = a-1; i >= 0; --i, potega *= 10) {
        arabska += t[i] * potega;
    }

    Pozdrawiam,
    Dr.Vee
  • Poziom 11  
    No to jest jeszcze jeden problem, z tego co zauważyłem, to licząc arabską on bierze wartości z kodu ASCII, wykomentowałem cześc zamieniającą liczbę na rzymską i po wpisaniu 1 uzyskałem arabską = 49. Jak zamieniac liczby z t[i] na cyfry 0-9 przed pomnożeniem przez potega?

    Jest bardzo niedobrze, bo nawet jak już maksymalnie ułatwię programowi sprawę, to wywala błąd systemu.
  • VIP Zasłużony dla elektroda
    Code:
    char cyfra;
    
    int liczba = cyfra - '0';

    Jeśli potraktujesz znak jako liczbę, to dostaniesz kod ASCII. Ponieważ cyfry w tablicy ASCII mają kolejne kody, to wystarczy odjąć od kodu znaku kod pierwszej cyfry, czyli '0'.

    Pozdrawiam,
    Dr.Vee
  • Poziom 11  
    A co może być powodem (po pomyslnym skompilowaniu programu) tego, że microsoft wywala mi błąd i kończy aplikacje po wprowadzeniu liczby z klawiatury?
  • VIP Zasłużony dla elektroda
    Niepoprawny dostęp do pamięci.
    Pokaż ładnie sformatowany kod, to się zobaczy gdzie masz błąd :)

    Pozdrawiam,
    Dr.Vee
  • Poziom 11  
    No to prosze:
    Code:
    #include <stdio.h>
    
    #include <stdlib.h>

    int rozpoznawacz(char t[],int a){   //funkcja dostaje do przeanalizowania tablice znakow i jej dlugosc, gwarantuje tez, ze nie bedzie ujemna i niecalkowita
        int mozliwosc[3];
        int i;
            for (i=0;i<3;i++){
            mozliwosc[i]=0;
            }     // wyzerowanie tablicy mozliwych mozliwosci
            for (i=0;i<a; i++) {
                if (t[i]>47&&t[i]<58) mozliwosc[0]=1;
                else if (t[i]=='i'||t[i]=='v'||t[i]=='x'||t[i]=='l'||t[i]=='c'||t[i]=='d'||t[i]=='m'||t[i]=='I'||t[i]=='V'||t[i]=='X'||t[i]=='L'||t[i]=='C'||t[i]=='D'||t[i]=='M') mozliwosc[1]=1;
                else mozliwosc[2]=1;
                }//1 w nastepujacych polach tablicy oznacza zawartosc: mozliwosc[0] - znakow arabskich; 1 - znakow rzymskich; 2 - inych znakow
                int opcja;
            if (mozliwosc[0]==1&&mozliwosc[1]!=1&&mozliwosc[2]!=1) opcja=0;
            else if (mozliwosc[1]==1&&mozliwosc[0]!=1&&mozliwosc[2]!=1) opcja=1;
                 else opcja=2;
       
        return opcja;
    }

    char konwerterAdoR(char t[], int a){
         char rzymska[79];
         long int arabska=0;
         int potega=1,i;
             for(i=a-1;i>=0;--i,potega*=10) {
             arabska+=(t[i]-'0')*potega;
             }
             i=0;
             if (arabska<4000000&&arabska>3999){
                do{
                   if (arabska>=1000000){
                       rzymska[i]='M';
                       arabska-=1000000;
                       i++;                 
                   }
                   else if (arabska>=900000){
                       rzymska[i]='C';
                       rzymska[i+1]='M';
                       arabska-=900000;
                       i+=2;                 
                   }
                   else if (arabska>=500000){
                       rzymska[i]='D';
                       arabska-=500000;
                       i++;                 
                   }
                   else if (arabska>=400000){
                       rzymska[i]='C';
                       rzymska[i+1]='D';
                       arabska-=400000;
                       i+=2;                 
                   }
                   else if (arabska>=100000){
                       rzymska[i]='C';
                       arabska-=100000;
                       i++;                 
                   }
                   else if (arabska>=90000){
                       rzymska[i]='X';
                       rzymska[i+1]='C';
                       arabska-=90000;
                       i+=2;                 
                   }
                   else if (arabska>=50000){
                       rzymska[i]='L';
                       arabska-=50000;
                       i++;                 
                   }
                   else if (arabska>=40000){
                       rzymska[i]='X';
                       rzymska[i+1]='L';
                       arabska-=40000;
                       i+=2;                 
                   }
                   else if (arabska>=10000){
                       rzymska[i]='X';
                       arabska-=10000;
                       i++;                 
                   }
                   else if (arabska>=9000){
                       rzymska[i]='I';
                       rzymska[i+1]='X';
                       arabska-=9000;
                       i+=2;                 
                   }
                   else if (arabska>=5000){
                       rzymska[i]='V';
                       arabska-=5000;
                       i++;                 
                   }
                   else if (arabska>=4000){
                       rzymska[i]='I';
                       rzymska[i+1]='V';
                       arabska-=4000;
                       i+=2;                 
                   }
                   else if (arabska>=1000){
                       rzymska[i]='I';
                       arabska-=1000;
                       i++;                 
                   }
                   else if (arabska>=900){
                       rzymska[i]='c';
                       rzymska[i+1]='m';
                       arabska-=900;
                       i+=2;                 
                   }
                   else if (arabska>=500){
                       rzymska[i]='d';
                       arabska-=500;
                       i++;                 
                   }
                   else if (arabska>=400){
                       rzymska[i]='c';
                       rzymska[i+1]='d';
                       arabska-=400;
                       i+=2;                 
                   }
                   else if (arabska>=100){
                       rzymska[i]='c';
                       arabska-=100;
                       i++;                 
                   }
                   else if (arabska>=90){
                       rzymska[i]='x';
                       rzymska[i]='c';
                       arabska-=90;
                       i+=2;                 
                   }
                   else if (arabska>=50){
                       rzymska[i]='l';
                       arabska-=50;
                       i++;                 
                   }
                   else if (arabska>=40){
                       rzymska[i]='x';
                       rzymska[i+1]='l';
                       arabska-=40;
                       i+=2;                 
                   }
                   else if (arabska>=10){
                       rzymska[i]='x';
                       arabska-=10;
                       i++;                 
                   }
                   else if (arabska>=9){
                       rzymska[i]='i';
                       rzymska[i+1]='x';
                       arabska-=9;
                       i+=2;                 
                   }
                   else if (arabska>=5){
                       rzymska[i]='v';
                       arabska-=5;
                       i++;                 
                   }
                   else if (arabska>=4){
                       rzymska[i]='i';
                       rzymska[i]='v';
                       arabska-=4;
                       i+=2;                 
                   }
                   else if (arabska>=1){
                       rzymska[i]='i';
                       arabska-=1;
                       i++;                 
                   }
           
                } while (arabska!=0);
             }
             else if (arabska<4000&&arabska!=0) {
                do{
                 
                    if (arabska>=1000){
                       rzymska[i]='m';
                       arabska-=1000;
                       i++;                 
                   }
                   else if (arabska>=900){
                       rzymska[i]='c';
                       rzymska[i+1]='m';
                       arabska-=900;
                       i+=2;                 
                   }
                   else if (arabska>=500){
                       rzymska[i]='d';
                       arabska-=500;
                       i++;                 
                   }
                   else if (arabska>=400){
                       rzymska[i]='c';
                       rzymska[i+1]='d';
                       arabska-=400;
                       i+=2;                 
                   }
                   else if (arabska>=100){
                       rzymska[i]='c';
                       arabska-=100;
                       i++;                 
                   }
                   else if (arabska>=90){
                       rzymska[i]='x';
                       rzymska[i]='c';
                       arabska-=90;
                       i+=2;                 
                   }
                   else if (arabska>=50){
                       rzymska[i]='l';
                       arabska-=50;
                       i++;                 
                   }
                   else if (arabska>=40){
                       rzymska[i]='x';
                       rzymska[i+1]='l';
                       arabska-=40;
                       i+=2;                 
                   }
                   else if (arabska>=10){
                       rzymska[i]='x';
                       arabska-=10;
                       i++;                 
                   }
                   else if (arabska>=9){
                       rzymska[i]='i';
                       rzymska[i+1]='x';
                       arabska-=9;
                       i+=2;                 
                   }
                   else if (arabska>=5){
                       rzymska[i]='v';
                       arabska-=5;
                       i++;                 
                   }
                   else if (arabska>=4){
                       rzymska[i]='i';
                       rzymska[i]='v';
                       arabska-=4;
                       i+=2;                 
                   }
                   else if (arabska>=1){
                       rzymska[i]='i';
                       arabska-=1;
                       i++;                 
                   }
                } while (arabska!=0);
             }
                 else rzymska[78]=1; //swiadczy to o tym, ze liczba jest wieksza od 3999999 lub 0
                 
                 return rzymska[79];
                 
    }

    int main (void){
       char czy_dalej;
       do{
       int d;
       int a;
        char liczba[79];
        char wynik[79];
        int rodzaj;
           printf("Podaj liczbe w systemie arabskim lub rzymskim.\nLiczba rzymska zapisana wielkimi literami oznacza 1000 razy wieksza liczbe,\na malymi, normalna. Musi byc mniejsza od 4mln.\n");
            scanf("%79s", liczba);
                          d=strlen(liczba);
            rodzaj=rozpoznawacz(liczba,d);
                if (rodzaj==0){
                   printf("%s", konwerterAdoR(liczba,d));
                }
                else if (rodzaj==1){
                   printf("rzymska");
                } 
                else printf("Blad przy wpisaniu liczby.\n\n");
           
            printf("Chcesz przekonwertowac nastepna liczbe, klik T.\n\n");
            scanf(" %c", &czy_dalej);
        } while(czy_dalej=='T'||czy_dalej=='t');
           
        system("PAUSE");
    }
  • VIP Zasłużony dla elektroda
    Straszny kod ;) Taką konwersję najprościej załatwia się tablicą:
    Code:
    struct cyfraRzymska {
    
       unsigned wartosc;
       const char* napis;
    } konwersje[] = {
        {1000, "m"},
        {900,   "cm"},
        /* itd, itd */
        {1, "i"}
    };


    Do rzeczy - masz błąd, bo wywołujesz
    Code:
    printf("%s", konwerterAdoR(liczba, d));
    ale konwerterAdoR zwraca char - a Ty potrzebujesz char*.
    Code:
    return liczba[79]
    nie zwraca tablicy, tylko 80-ty znak z tablicy (która nota bene ma tylko 79 elementów...). Poza tym nie możesz zwrócić np. wskaźnika do tablicy lokalnej (liczba jest zmienną lokalną), bo po powrocie z funkcji ta pamięć zostanie automatycznie zwolniona.

    Proponuję tak:
    Code:
    char* konwerterAdoR(char t[], int a, char r[], int b);
    Czyli przekazujesz do konwertera tablicę źródłową (i liczbę elementów) oraz tablicę z miejscem na wyniki (i rozmiar tego miejsca). Zwracasz (dla wygody) wskaźnik na pierwszy element tablicy wynikowej (pamiętaj, żeby po ostatnim elemencie w tablicy wynikowej wstawić '\0').

    Pozdrawiam,
    Dr.Vee
  • Poziom 11  
    Jeśli chodzi o wstawienie '\0' to ma to wyglądać:
    Code:
    r[i]='\0';
    czy tak:
    Code:
    r[i]=\0;
    ?
    Druga sprawa, jak funkcja char* zwróci pierwszy element tablicy wyniku, to jak mam się "dopraszać" o kolejne elementy?

    Teraz sobie pomyślałem, że można by zrobić coś tego typu: w main przerobić tablicę cyferek na liczbę, podać ją funkcji long int konwerterAdoR, a funkcja już w trakcie odbywania się będzie drukować poszczególne znaczki. Tylko to by było mniej eleganckie. Ale może prostsze?
  • VIP Zasłużony dla elektroda
    Albo
    Code:
    r[i]='\0';
    albo
    Code:
    r[i]=0;

    W języku C nazwa tablicy może być traktowana jako wskaźnik na pierwszy element tablicy (i na odwrót). Na przykład
    Code:
    char *wskaznik;
    
    char tablica[20];
    *(wskaznik + i) == tablica[i];

    Dobrze, że zauważyłeś, że rozwiązanie z obliczaniem i wypisywaniem w jednej funkcji jest mało eleganckie :)

    Pozdrawiam,
    Dr.Vee
  • Poziom 11  
    Dobra, serio próbowałem to zrozumieć, czy mógłbym prosić o kawałek kodu funkcji konwerterAdoR załatwiający kluczowe momenty a dokładnie:
    to z returnem (co w końcu tam ma stać?)
    po co dawać długośc miejsca na rzymską?

    oraz kawałek kodu w mainie "przejmujący" wynik z konwertera?
  • VIP Zasłużony dla elektroda
    padalec007 napisał:
    to z returnem (co w końcu tam ma stać?)

    Nic nie musisz zwracać. Funkcja przecież zwraca dane zapisując je do tablicy przekazanej jej jako parametr.
    padalec007 napisał:
    po co dawać długośc miejsca na rzymską?
    Bo skąd funkcja wywoływana ma wiedzieć ile jest wolnego miejsca w tablicy, którą dostaje? Jeśli nie przekażesz rozmiaru, to funkcja wywoływana i wszystkie funkcje wywołujące muszą zakładać taki sam rozmiar tablicy. W małym programie to działa, w dużym często powoduje problemy.

    Przykładowy kod:
    Code:
    int aToR(char arabska[], int arabska_len, char rzymska[], int rzymska_maxlen) {
    
        int zapisano_znakow = 0;
        /* konwertujesz, zwiększasz zapisano_znakow */
        /* jednoczesnie sprawdzasz, czy nie przekraczasz rzymska_maxlen-1 */
        /* -1 dlatego, że potrzebujesz ostatniego znaku na znak '\0' */
        rzymska[zapisano_znakow] = '\0';
        return zapisano_znakow;
    }

    /* wywolanie funkcji */
    int main(void) {
        char liczba_arabska[] = "12345";
        char wynik[30];
        int dlugosc_wyniku = 0;
        dlugosc_wyniku = aToR(liczba_arabska, sizeof(liczba_arabska), wynik, sizeof(wynik));
        if (dlugosc_wyniku > 0) {
            /* zakładamy, że wartość 0 lub ujemna oznacza błąd konwersji */
            printf("Liczba arabska = %s, liczba rzymska = %s\n",
                liczba_arabska, wynik);
            return 0;
        } else {
            printf("Liczba arabska = %s, błąd konwersji!\n", liczba_arabska);
            return 1;
        }
    }

    Pozdrawiam,
    Dr.Vee
  • Poziom 11  
    O kurcze! działa...

    To przyszła pora na arabskie z rzymskich... ech :/
  • VIP Zasłużony dla elektroda
    padalec007 napisał:
    O kurcze! działa...

    Prawdziwy z Ciebie programista - bezcenne zdziwienie jak w końcu zadziała ;)

    padalec007 napisał:
    To przyszła pora na arabskie z rzymskich... ech :/


    Gdybyś napisał program w oparciu o tablicę zmian, to miałbyś teraz dużo mniej roboty :)

    Pozdrawiam,
    Dr.Vee
  • Poziom 20  
    O ile dobrze wyliczyłem, to po 6 dniach, 1 godzinie i 22 minutach nastąpił sukces:
    Cytat:
    O kurcze! działa...


    Proponuję algorytm "na siłę":
    - generować w pętli kolejne liczby rzymskie
    - porównywać wygenerowaną liczbę rzymską z liczbą podaną z klawiatury
    - przerwać pętlę, gdy nastąpi sukces (będzie szybciej niż 6 dni)
    - jeśli pętla zakończy się bez sukcesu, to znaczy że wprowadzony napis nie jest liczą rzymską!:D
  • Poziom 11  
    wrych napisał:
    O ile dobrze wyliczyłem, to po 6 dniach, 1 godzinie i 22 minutach nastąpił sukces
    Taaaak :D

    wrych napisał:
    Proponuję algorytm "na siłę":
    - generować w pętli kolejne liczby rzymskie
    - porównywać wygenerowaną liczbę rzymską z liczbą podaną z klawiatury
    - przerwać pętlę, gdy nastąpi sukces (będzie szybciej niż 6 dni)
    - jeśli pętla zakończy się bez sukcesu, to znaczy że wprowadzony napis nie jest liczą rzymską!:D

    Kurcze to genialne! Chyba tak zrobie, dzięki!
  • Poziom 11  
    E nie, jednak tak nie zrobię, bo pętla w najgorszym wypadku wykonywała by się 4 mln. razy. A to pewnie trwałoby tyle, że można by w tym czasie zamówić pizzę. Dlatego wymyśliłem swój wspaniały algorytm do zamiany rzymskich na arabskie, z tym, że nie wiem jak zapisać liczbę arabską (o długości nawet do 7 znaków) typu long int do tablicy char po jednym znaku na komórkę?
  • Poziom 20  
    Pomyśl jak programista (o podprogramach) - wystarczy Ci 4000 powtórzeń pętli x 2:
    - najpierw liczby typu "MMCDXLVII", czyli wg Twojej notacji "tysiące"
    - potem to samo dla liczb typu "mmcdxlvii", czyli "jedności".
    A potem to już tylko jedno mnożenie i jedno dodawanie :D.
    Ciekawe skąd wziąłeś taką konwencję zapisu liczb rzymskich?

    A tak poważnie, to spróbuj zrobić to tak:
    - w ciągu znaków (liter) reprezentujących liczbę rzymską szukaj par znaków CM, CD, XC, XL, IX, IV (każda para może wystąpić tylko raz!)
    - przyjmij arabska=0
    - jeśli w zapisie występuje jakaś w ww. par znaków, to usuń ją z zapisu liczby rzymskiej i odpowiednio zwiększ wartość liczby arabskiej (arabska+=coś, gdzie coś jest równe właściwej z liczb: 900, 400, 90, 40, 9 lub 4)
    - eliminuj z zapisu liczby rzymskiej kolejno znaki (mogą występować teraz tylko raz) D, L, V i odpowiednio zwiększaj wartość zmiennej arabska (o 500, 50 lub 5)
    - eliminuj z zapisu liczby rzymskiej kolejno znaki (mogą powtarzać się do 3 razy) M, C, X, I i odpowiednio zwiększaj wartość zmiennej "arabska" (o 1000, 100, 10 lub 1)
    - jak zabraknie znaków, to "arabska" zawiera wynik.
    I to by było na tyle, jak mawiał Ś.P. J.T. Stanisławski.

    PS. Wszystko fajnie gdy podana liczba jest poprawnie, np. "MMCDXLVII".
    Trzeba zastanowić się jeszcze jak wyeliminować przypadek "IC" (poprawnie powinno być "XCIX") lub inne bzdury.