Caesar (Цезарь)

Коротко

Создайте программу, которая будет шифровать текст, используя “Шифр Цезаря”.

$ ./caesar 13
plaintext:  HELLO
ciphertext: URYYB

Объяснение

Предположим, что Цезарь (да, тот самый Цезарь, пусть будет Юлием) “шифровал” важные сообщения (т.е. засекречивал обратимым способом), смещая каждую букву определенным количеством позиций. К примеру, он мог записать A как B, B как C, C как D и, дойдя до Z, начать алфавит с начала и написать A (Z как A). Поэтому, чтобы кому-нибудь передать сообщение HELLO (привет), Цезарь мог бы написать IFMMP. Получив такого вида сообщения, адресатам пришлось бы заниматься их “декодированием” путем смещения букв в противоположном направлении, используя то же количество позиций.

Секретность этой “криптосистемы” держится только на Цезаре и на получателях сообщений, знающих секрет - количество произведенных Цезарем смещений букв в его сообщении (т.е. 1 позиция). Не очень надежный метод по современным стандартам, но если бы вы были первым человеком применившим этот метод, получилось бы довольно надежно!

Незашифрованным текстом обычно называют plaintext (простой текст). Засекреченным текстом - ciphertext (шифрованный текст). И используемым секретом выступает key (ключ).

Таблица 1. Шифрование слова HELLO ключом “1” дает результат IFMMP.

простой текст H E L L 0
+ ключ 1 1 1 1 1
= зашифрованный текст I F M M P

В общем алгоритм (шифр) Цезаря — это вид шифра подстановки, в котором каждый символ заменяется символом, находящимся на k позиций левее или правее него в алфавите. Если переменная p будет хранить в себе простой текст (т.е. не зашифрованное сообщение ), pi представляет iую (айную) букву переменной p, и k - это секретный ключ (неотрицательное целое число). Тогда каждая буква ci в зашифрованном тексте переменной c, рассчитывается следующим образом

ci=(pi+k) mod 26

где mod 26 означает “остаток после деления на 26.” Может показаться, что эта формула только усложняет шифр, но на самом деле это просто более точный способ выразить алгоритм необходимых действий.

Описание

Разработайте и реализуйте программу caesar, которая будет шифровать сообщения используя шифр Цезаря.

Начните писать вашу программу в файле caesar.c, который будет находиться в папке caesar.

Ваша программа должна принимать только один аргумент командной строки - неотрицательный integer. Дайте ему название k, чтобы было понятно, о чем мы ведем речь.

Если ваша программа будет запущена без каких-либо дополнительных аргументов командной строки или с количеством превышающим один аргумент, она должна будет вывести на экран ошибку (пользуйтесь printf, текст ошибки на ваше усмотрение) и при этом main должна сразу вернуть значение 1 (обычно ею обозначают ошибку).

Будем считать, что пользователь будет вводить неотрицательный integer (т.е. 1). Не нужно проверять, числовое это значение или нет.

Не надо ограничивать переменную k, записывая код так, что она будет меньше или равна числу 26 (количество букв в английском алфавите). Ваша программа должна работать со всеми неотрицательными целыми числами k, которые будут меньше 231 - 26. Другими словами, вам не нужно бояться, что ваша программа может перестать работать, если пользователь предоставит слишком огромное значение k, под которое у int может не хватить памяти (Вспомните переполнение int - overflow). Алфавитные буквы были у вас на входе (то, что ввел пользователь) и алфавитные буквы должны также быть на выходе (то, что в итоге выведится на экран), даже если значение k будет больше 26. К примеру, если k равняется 27, то A не должна быть заменена символом [, хотя [ и находится в 27 позициях от буквы A в таблице ASCII (как показано здесь asciichart.com). На месте A должна появиться B, так как B на 27-й позиции от A, учитывая что после Z мы снова начинаем с A.

Ваша программа должна вывести на экран plaintext: (“простой текст”, обязательно на английском, без новой строки, т.е. без \n ) и попросить пользователя ввести простой текст типа string (используя get_string).

Ваша программа должна вывести на экран ciphertext: (“зашифрованный текст”, обязательно на английском, без новой строки, т.е. без \n ) сразу после чего выводится зашифрованный текст, где каждая алфавитная буква была смещена другой, находящейся в k позициях от нее; неалфавитные символы должны быть выведены на экран без изменений.

Ваша программа не должна изменять регистр: заглавные буквы, хоть и смещенные, должны оставаться заглавными; строчные буквы, хоть и смещенные, должны оставаться строчными.

После выведения зашифрованного текста, вы должны также вывести на экран новую строку. Далее ваша программа должна завершить свою работу, вернув число 0 - результат выполненной работы функции main.

Использование

Ваша программа должна проделывать тоже самое, что показано в примере ниже.

$ ./caesar 1
plaintext:  HELLO
ciphertext: IFMMP
$ ./caesar 13
plaintext:  hello, world
ciphertext: uryyb, jbeyq
$ ./caesar 13
plaintext:  be sure to drink your Ovaltine
ciphertext: or fher gb qevax lbhe Binygvar
$ ./caesar
Usage: ./caesar k
$ ./caesar 1 2 3 4 5
Usage: ./caesar k

Проверка

check50 cs50/2018/x/caesar

Стиль

style50 caesar.c

Закачать

submit50 check50 cs50/2018/x/caesar

Вас потребуют ввести логин (GitHub username) и пароль (GitHub password) от вашей учетной записи на Github’е, которую вы можете завести, пройдя по данной ссылке https://github.com/join.

Зайдите на сайт cs50.me, используя всё ту же учетную запись GitHub’а и нажмите на зеленую кнопку authorize submit50 (Это действие производится только один раз).

Подсказки

Программа должна принимать один аргумент командной строки k, поэтому вам нужно объявить функцию main следующим образом:

int main(int argc, string argv[])

Вспомните, что argv является массивом strings (строк). Вы можете представить массив в виде ряда шкафчиков в раздевалке гимнастов, внутри которых находятся какие-то значения (возможно даже носки). В нашем случае внутри каждого такого шкафчика находится string. Чтобы открыть (т.е. “получить доступ через индекс”) первый шкафчик, вы должны воспользоваться синтаксисом argv[0], так как в массиве индексация начинается с нуля. Следующий можете открыть синтаксисом argv[1] и так далее. Конечно, если у вас всего n шкафчиков, то вам лучше всего закончить весь этот процесс открывания шкафчиков в раздевалке, как только вы дойдете до argv[n - 1] (или охранника), так как argv[n] не существует! (или же он принадлежит кому-нибудь другому, в любом случае вам нельзя его открывать.)

Вы можете присвоить значение переменной k следующим кодом

string k = argv[1];

предполагая, что она действительно там! Вспомните, что argc является int, который равен числу строк (strings), находящихся в argv, поэтому лучше всего сперва проверить значение argc до того как пытаться открыть шкафчик, которого вовсе может и не быть! В идеале argc должен равняться 2. Почему? Вспомните, что внутри argv[0] по умолчанию находится название самой программы. Поэтому значение argc будет всегда как минимум равняться 1. Но для этой программы вам нужно получить от пользователя аргумент командной строки k, что присваивает argc значение 2. Конечно, если пользователь предоставит больше одного аргумента командной строки, значение argc может стать больше 2 и если такое произойдет, ваша программа должна будет вывести ошибку и вернуть число 1.

То, что пользователь введет целое число, не означает, что его ввод автоматически будет помещен в int. Совсем наоборот, он будет сохранен как string (строка), которая, так уж получилось, будет выглядеть как int! Поэтому вам нужно будет преобразовать эту string в int. Нам повезло, что кто-то уже написал функцию делающую все это за нас - atoi. Вот как ей можно воспользоваться:

int k = atoi(argv[1]);

Заметьте, что на этот раз мы объявили переменную k, указав ее тип как int. Так вы сможете осуществлять над ней арифметические вычисления.

Так как atoi объявлен в библиотеке stdlib.h, вам нужно будет #include (включить) этот заголовочный файл (.h или .header) в верхнюю часть вашего кода (Ваш код итак будет компилироваться, если даже вы не будете включать ее, потому что мы уже #include (добавили) данную библиотеку в cs50.h. Но не стоит доверять другой библиотеке #include (включение) в ваш код необходимых вам заголовочных файлов.).

Как только в переменную k будет помещено значение типа int, вам нужно будет попросить пользователя ввести простой текст. Вполне вероятно, что функция библиотеки CS50 get_string сможет помочь вам с этим.

Как только вы получите k и какой-нибудь простой текст p, вы сможете начать шифровать буквы. Вспомните, что вы можете проводить итерацию (перебирание) каждой буквы string (строки), выводя их на экран, как показано ниже:

for (int i = 0, n = strlen(p); i < n; i++)
{
    printf("%c", p[i]);
}

Другими словами, точно также как argv является массивом strings (строк), так и string является массивом chars (символов). Значит вы можете использовать квадратные скобки для получения доступа к каждому символу по отдельности точно также, как вы это делали с argv для доступа к strings (строкам). Неплохо, да? Конечно, по отдельности выводить на экран символы - далеко не криптография. Конечно, если k не равен 0. Но все, что нами было приведено выше, поможет вам оказать помощь Цезарю в написании его шифра!

Между прочим, вам нужно будеть #include (включить) еще один заголовочный файл для того, чтобы иметь возможность пользоваться функцией strlen.

И по поводу обнуления индекса для повторного смещения с Z на A (или z на a) - не забывайте о %, операторе остатка (modulo) в языке программирования Си. Пользуйтесь http://asciitable.com/, таблица ASCII содержит в себе не только алфавитные буквы - это на всякий случай, вдруг вы случайно начнете выводить непонятные символы.