W szyfrze ułamków musimy zdefiniować ciąg liter, który będzie naszym alfabetem oraz klucz n, który jest liczbą całkowitą. Szyfrowanie polega na pogrupowanie liter w grupy po n kolejnych liter. Następnie szyfrując znak szukamy go w której grupie się znajduje. Po odnalezieniu zapisujemy kolejno, które miejsce zajmuje litera w grupie, znak "/" oraz numer grupy, gdzie znaleźliśmy znak. Wszystkie zaszyfrowane znaki rozdzielamy średnikiem. Znak spacji " " zastępujemy znakiem plusa "+". Ułamek przed znakiem spacji nie ma pos sobie średnika.
Przykładowo weźmy alfabet łaciński ABCDEFGHIJKLMNOPQRSTUVWXYZ i ustalmy klucz 5. Naszym pierwszym krokiem będzie pogrupowanie liter. Wynikiem tego jest ABCDE FGHIJ KLMNO PQRST UVWXY Z. Jeśli w danej grupie nie ma n znaków to może tak zostać, ponieważ nie ma to znaczenia. Teraz spróbujmy zaszyfrować tekst "INFORMACJA":
Litera | Nr. Grupy | Pozycja | Zapis |
---|---|---|---|
I | 2 | 4 | 2/4 |
N | 3 | 4 | 3/4 |
F | 2 | 1 | 2/1 |
O | 3 | 5 | 3/5 |
R | 4 | 3 | 4/3 |
M | 3 | 3 | 3/3 |
A | 1 | 1 | 1/1 |
C | 1 | 3 | 1/3 |
J | 2 | 5 | 2/5 |
A | 1 | 1 | 1/1 |
W ten sposób otrzymujemy szyfrogram: 2/4;3/4;2/1;3/5;4/3;3/3;1/1;1/3;2/5;1/1
Większość ułamków z matematycznego punktu widzenia jest skracalnych. Pod żadnym pozorem nie wolno w tym szyfrze skracać ułamków. Najlepszym przykładem jest 1/1, 2/2, 3/3, ... n/n. Z matematyki wynika , ale wtedy 1 może oznaczać dowolną i-tą grupę na i-tej pozycji. Innym przykładem jest 1/2 i 2/4.
Chcąc rozszyfrować bierzemy każdy kolejny ułamek. Licznik będzie wskazywał w której grupie jest znak, a licznik jego pozycję w wskazanej grupie. Przykładowo 3/5 to znak z trzeciej grupy na piątej pozycji czyli wg. przyjętego alfabetu litera W.
Na wejściu znajdą się dwie linijki danych. W pierwszej będzie liczba całkowita, która będzie długością podgrup. Druga linijka będzie to ciąg znaków, który będzie trzeba zaszyfrować zgodnie z szyfrem ułamkowym. Na wyjście powinien zostać wypisany wynik szyfrowania. Przykładowo dla:
otrzymamy:
Zakładamy, że alfabet jest dany i są nim wszystkie duże litery alfabetu łacińskiego od A do Z.
W celu optymalizacji wykorzystanie pamięci będziemy potrzebowali znać dokładną długość tekstu wynikowego co za tym idzie długość każdej liczby:
Dodatkowo napiszemy funkcję, która pozwoli zapisywać liczbę na tablicy znaków. Innymi słowy będzie konwertować liczbę na tekst. Wykorzystamy do tego pętle do ... while. Dzięki temu mamy pewność, że jeśli przepisywana liczba to 0 to ją zapiszemy w wyniku.
(1.) Funkcja nie zwraca żadnej wartości, jest ona bardziej częścią innej funkcji, ponieważ modyfikuje wartości jej przekazywane. Funkcja otrzymuje trzy argumenty: n - liczbę do przepisania, s - tablica char* do której przepisujemy kolejne cyfry oraz i - wskaźnik od którego miejsca w tablicy zaczynamy zapisywanie. (2.) Rozpoczynamy do ... while: (3.) Zapisujemy ostatnią cyfrę. (4.) Dzielimy liczbę przez 10, aby w następnej iteracji (jeśli będzie) pobrać następną cyfrę. (5.) Sprawdzamy warunek czy już przepisaliśmy całą liczbę.
Na początek wyliczymy długość tekstu wynikowego:
(1.) Przyjmujemy dwa argumenty: txt - tekst do zaszyfrowania oraz n - długość każdej podgrupy. (2.) Ustalamy długość na 0. (3.) Dla każdego znaku, który jest różny od spacji (czyli liter od A do Z) (4.) zwiększamy długość o 2 (znak "/" i ";"). Do tego dodajemy długość liczby grupy i pozycji.
(6.) Alokujemy pamięć pod wynik. (7.) Dla każdego znaku w tekście do zaszyfrowania (8.) jeśli jest znakiem spacji to (9.) wstawiamy na znak na pozycji j-1.
(10.) Jeśli jest to litera to zapisujemy do wyniku (11.) numer grupy, (12.) znak "/", (13.) numer pozycji oraz (14.) znak średnika ";". (17.) Na koniec dopisujemy znak końca danych zamiast ostatniego średnika i (18.) zwracamy wynik.
Do deszyfrowania przyda się funkcje pomocnicza, która wczyta liczbę z tablicy char*. Zakładamy, że wczytujemy liczbę dopóki mamy jakiekolwiek cyfry.
(1.) Jako argumenty dostajemy tablice char* oraz pozycję i. W ten sposób wiemy od którego miejsca mamy zacząć wpisywać liczbę. (2.) Początkowo liczba wynosi 0. (3.) Dopóki mamy jakąkolwiek cyfrę to (4.) przesuwamy cyfry i jedną w lewo czyli mnożymy razy 10 i (5.) dodajemy kolejną wczytana cyfrę z tekstu. (7.) Na koniec zwracamy wczytaną liczbę.
Tak samo jak w przypadku szyfrowania na początek obliczymy długość tekstu:
Każdy ułamek kończy się znakiem + lub ; i tylko ostatni ułamek nie ma ani jednego z wymienionych znaków. (2.) Deklarujemy długość tekstu na 0. (3.) Dla każdego znaku w szyfrogramie sprawdzamy czy wczytany jest znak / (który ma każdy ułamek) lub + (dodatkowe spacje). Kiedy zsumujemy wystąpienia oczytamy jak długi będzie tekst wynikowy.
(6.) Alokujemy pamięć pod wynik. (7.) Dla każdego ze znaków w szyfrogramie: (7.) wczytujemy dwie liczby na podstawie których wyliczamy jaka literę przedstawia wczytany ułamek. (8.) Sprawdzamy czy poprzednim znakiem nie jest + co by oznaczało, że musimy dostawić dodatkową spacje. (12.) Na koniec dopisujemy znak końca danych zamiast ostatniego średnika i (13.) zwracamy wynik.
Poniższa funkcja main() pozwala sprawdzić czy napisane funkcje działają poprawnie.
Na wejściu znajdą się trzy linijki danych. W pierwszej będzie ciąg znaków, który będzie przedstawiał alfabet, w drugiej liczba całkowita, która będzie długością podgrup. Trzecia linijka będzie to ciąg znaków, który będzie trzeba zaszyfrować zgodnie z szyfrem ułamkowym. Na wyjście powinien zostać wypisany wynik szyfrowania. Przykładowo dla:
otrzymamy:
Dotychczasowy kod potrzebuje drobnej modyfikacji. Podczas szyfrowania nie możemy wyliczać grupy i pozycji na podstawie odległości od litery A. Wyliczymy je na podstawie pozycji znaku w podanym alfabecie. Żeby to osiągnąć dopiszemy funkcję, która dla podanego ciągu i znaku znajdzie jego pozycję i ją zwróci.
Spójrzmy teraz na funkcję szyfrującą:
Zmodyfikowane są linijki (5.), (11.) i (13.), gdzie zastępujemy wyliczanie grupy i pozycji znaku - nie na podstawie tablicy ASCII, a na podstawie podanego alfabetu.
W funkcji rozszyfrowującej podajemy dodatkowy argument alphabet. Trzeba zmienić tylko linijkę (9.), gdzie nie wyliczamy znaku na podstawie tablicy ASCII, a pobieramy wyliczoną pozycję z tablicy alphabet.
Na podstawie kodu źródłowego do zadania 2: