Следующий код изменяет буквы ввода на k. k — первый аргумент. Например, если ввод должен быть изменен на 2 буквы, аргумент командной строки будет "./caesar 2", если три, то "./caesar 3". и т.п. Изменение букв означает, например, изменение на 2, тогда ввод «a» становится «c». Изменение на 3 означает, что ввод «abc» становится «def» и т. д. Ввод, предоставленный пользователем, проверяется, если (а) числовые аргументы точно равны 2, (б) аргумент является числом.
Код, выполняемый так, как код написан ниже, укорачивается на одну букву. Например, «hello», измененное на 1 букву, становится «iffm». Если введена только одна буква, отображается правильный вывод, за которым следуют некоторые неопределенные буквы. Например, «a» становится «b��P», или «bm>�», или «b;����».
Когда либо (1) проверка ввода (b) [если аргумент является числом] удаляется ИЛИ (2) строка printf со случайным оператором (это может быть даже пустая строка) вставляется ТОЧНО между функцией get_string, когда запрашивая у пользователя ввод и цикл for, при изменении букв вывод соответствует назначению. Или (3) если последний символ ввода является специальным символом, вывод будет таким, как ожидалось (специальным символом является любой неалфавитный символ). например, "привет1" или "привет!" измененный на одну букву становится "ifmmp1" или "ifmmp!".
Я действительно в отчаянии, и я не знаю, что происходит и, что более важно, почему это происходит. Итак, мои вопросы: (1) Почему вывод сокращен на одну букву? Почему вывод неправильный, когда на входе только одна буква? (думаю проблема та же). (2) (a) Почему выход изменяется, когда либо убирают числовую проверку, либо (b) случайная строка printf вставляется точно между указанными выше строками или (c) последний символ не является буквенным?
Я очень ценю любую помощь и, пожалуйста, извините за странный английский, поскольку это не мой родной язык :). Большое спасибо! Отчаянный ученик кода :)
Это код:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
bool isNumber(string numberToCheck);
int main(int argc, string argv[])
{
// checking, if arguments are correct
// checking, if input is correct (i.e. 2)
if (argc != 2)
{
printf("Usage: ./cesar key\n");
exit(1);
}
// checking, if input is a number, if the following if statement is removed the output changes
if (!isNumber(argv[1]))
{
printf("Usage: ./caesar key\n");
exit(1);
}
// variables
int k = atoi(argv[1]);
string plaintext;
int plaintextLength;
// getting the plaintext from user input, creating ciphertext string of same length
plaintext = get_string("paintext: ");
// checking the length of the input
plaintextLength = strlen(plaintext);
//the output changes, when the next line is being inserted
printf("");
// creating new empty string with plaintextLength
char ciphertext[plaintextLength];
// iterating through plaintext char by char
for(int i = 0; i < plaintextLength;i++)
{
// in case of capital letter
if (plaintext[i] >= 65 && plaintext[i] <= 90)
{
ciphertext[i] = 65 + (((plaintext[i] - 65) + k) % 26);
}
// else in case of small letter
else if (plaintext[i] >= 97 && plaintext[i] <= 122)
{
ciphertext[i] = 97 + (((plaintext[i] - 97) + k) % 26);
}
// else in case of non alphabetical letter
else
{
ciphertext[i] = plaintext[i];
}
}
printf("ciphertext: %s\n", ciphertext);
}
bool isNumber(string numberToCheck)
{
for(int i = 0;i < strlen(numberToCheck); i++)
{
if (!isdigit(numberToCheck[i]))
{
return false;
}
}
return true;
}
Покажи нам get_string
.
plaintextLength
— длина строки, то есть количество символов в строке, не считая завершающего нуля. Это означает, что в ciphertext[plaintextLength]
нет места для нулевого терминатора в конце, который требуется для строк C. Вам нужно добавить 1 дополнительное место для нулевого терминатора и установить содержимое этого места на 0.
Правильным шифрованием hello
является ifmmp
, а не iffm
, как вы утверждаете.
int i;
// iterating through plaintext char by char
for(i = 0; i < plaintextLength;i++)
{
// in case of capital letter
if (plaintext[i] >= 65 && plaintext[i] <= 90)
{
ciphertext[i] = 65 + (((plaintext[i] - 65) + k) % 26);
}
// else in case of small letter
else if (plaintext[i] >= 97 && plaintext[i] <= 122)
{
ciphertext[i] = 97 + (((plaintext[i] - 97) + k) % 26);
}
// else in case of non alphabetical letter
else
{
ciphertext[i] = plaintext[i];
}
}
ciphertext[i] = '\0';
printf("ciphertext: %s\n", ciphertext);
}
В C каждая строка использует \0, чтобы сообщить компьютеру, что она достигла конца строки.
Без этого завершающего оператора NULL компьютер может попытаться прочитать строку в память, поэтому вы сталкиваетесь со случайными символами.
Поэтому, когда вы создаете строку, не забудьте добавить \0 в конце, это то, что я сделал с вашим кодом здесь. Я объявил «i» вне цикла for, чтобы он не переставал существовать в конце цикла. Когда вы дойдете до конца цикла, «i» будет равно длине вашей строки.
Если мой открытый текст — «лол», а ключ — 5, «i» будет равен 3, а зашифрованный текст будет «qtq». Шифрованный текст[i] будет указывать сразу после последней «q», так как мы считаем с 0, и именно здесь вы хотите поместить свой \0.
Также есть опечатка в вашей getstring.
Надеюсь, мое объяснение понятно, если у вас есть какие-либо вопросы, просто спросите :)
Вы не завершаете строку 0.