I'm working on a program that uses ciphers. The Cipher I need to use is the alphabet to qwerty. So...
abcdefghijklmnopqrstuvwxyz
qwertyuiopasdfghjklzxcvbnm
the program needs to take the encoding key
qwertyuiopasdfghjklzxcvbnm
and produce the decoding key.
How would I go about doing this? I've only done a Caesar Cipher in the past.
Here is the code in C to convert a string input to qwerty cipher, assuming you're working with only lowercase letters, and using a buffer size of 500 for strings:
#include <stdio.h>
#include <string.h>
int main() {
char* ciphertext = "qwertyuiopasdfghjklzxcvbnm"; // cipher lookup
char input[500]; // input buffer
printf("Enter text: ");
fgets(input, sizeof(input), stdin); // safe input from user
input[strlen(input) - 1] = 0; // remove the \n (newline)
int count = strlen(input); // get the string length
char output[count]; // output string
for(int i = 0; i < count; i++) { // loop through characters in input
int index = ((int) input[i]) - 97; // get the index in the cipher by subtracting 'a' (97) from the current character
if(index < 0) {
output[i] = ' '; // if index < 0, put a space to account for spaces
}
else {
output[i] = ciphertext[index]; // else, assign the output[i] to the ciphertext[index]
}
}
output[count] = 0; // null-terminate the string
printf("output: %s\n", output); // output the result
}
Related
I'm working on a program that is supposed to take a key as an input argument, and encrypt a user input word using this key.
The program should:
Ask the user for a plaintext word to encrypt
Standardize the letter case
Take each letter from the plaintext and find the index of this letter (A = 0, B = 1,...)
Look at the letter indexed at this location in the key string (input argument)
Assign this encrypted letter to a new sting called cypher
Print the new cyphertext string.
The code I'm using is this:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{
//Check that key has 26 letters or end program
string key = argv[1];
if (strlen(argv[1]) != 26)
{
printf("Key must contain 26 characters\n");
return 1;
}
//Get plaintext
string plain = get_string("plaintext: ");
//Make key all letters upper case
for (int i = 0; i < plain[i]; i++)
{
if (islower(plain[i]))
{
plain[i] = plain[i] - 32;
}
printf("%c", plain[i]);
}
printf("\n");
//Encrypt
int index[] = {};
int cypher[] = {};
//Cycle through the letters in the word to be encoded
//printf("cyphertext: ");
printf("%c\n", key[79 - 65]);
for (int i = 0; i < strlen(plain); i++)
{
printf("index in key: %i\n", plain[i] - 65);
cypher[i] = key[plain[i] - 65];
printf("cypher: %c\n", cypher[i]);
}
printf("\n");
}
Everything executes fine until the fourth loop of the for loop that assigns the new values to the cypher string. When the program tries to set i = 4, I get the error Segmentation fault (core dumped)
I was expecting the last for loop to loop once for each letter of the input (e.g. input: hello; loops: 5), but I found that it stops at 4 and only outputs: 'HELL'.
I tried:
Words with 4 characters - executes the correct number of loops, but I still get Segmentation fault (core dumped) after the final loop
Words with 3 characters - executes fine, no error
Words with 5+ letters - Still loops 4 times before error
Please help!
The for loop should iterate from 0 to length of plain.
//Get plaintext
string plain = get_string("plaintext: ");
//Make key all letters upper case
for (int i = 0; i < strlen(plain); i++)
{
if (islower(plain[i]))
{
plain[i] = plain[i] - 32;
}
printf("%c", plain[i]);
}
//*** Must allocate memory for array
//Encrypt
int index[100] = {};
int cypher[100] = {};
//Cycle through the letters in the word to be encoded
//printf("cyphertext: ");
printf("%c\n", key[79 - 65]);
for (int i = 0; i < strlen(plain); i++)
{
printf("index in key: %i\n", plain[i] - 65);
cypher[i] = key[plain[i] - 65];
printf("cypher: %c\n", cypher[i]);
}
printf("\n");
So the goal of this program is to basically take a 26 letter 'key' in the terminal (through argv[]) and use its index's as a substitution guideline. So there are 2 inputs you enter in the terminal, one in the argv[] and one is just a plain get_string() input. The argv[] input will look like this: ./s YTNSHKVEFXRBAUQZCLWDMIPGJO where s is the file name. And then the get_string() input will look like this: plaintext: HELLO. (The input is HELLO). What the program will then do is loop through all the letters in the plaintext input and substitute its alphabetical index according to the index of the argv[] key. For example, H has an alphabetical index of 7 (where a = 0 and z = 25), so we look at the 7th index in the key YTNSHKV(E)FXRBAUQZCLWDMIPGJO which in this case is E. It does this for each letter in the input and we'll end up with the output ciphertext: EHBBQ. This is what it should look like in the terminal:
./s YTNSHKVEFXRBAUQZCLWDMIPGJO
plaintext: HELLO
ciphertext: EHBBQ
But my output is EHBB, since it cuts off the last letter for some reason when I use toupper().
And also, the uppercase and lowercase depends on the plaintext input, if the plaintext input was hello, world and the argv[] key was YTNSHKVEFXRBAUQZCLWDMIPGJO, the output would be jrssb, ybwsp, and if the input was HellO, world with the same key, the output would be JrssB, ybwsp.
I'm basically done with the problem, my program substitutes the plaintext given into the correct ciphertext based on the key that was inputted through the command line. Right now, say if the plaintext input was HELLO, and the key was vchprzgjntlskfbdqwaxeuymoi (all lowercase), then it should return HELLO and not hello. This is because my program puts all the letters in the command line key into an array of length 26 and I loop through all the plaintext letters and match it's ascii value (minus a certain number to get it into 0-25 index range) with the index in the key. So E has an alphabetical index of 4 so in this case my program would get lowercase p, but I need it to be P, so that's why I'm using toupper().
When I use tolower(), everything worked fine, and once I started using toupper(), the last letter of the ciphertext is cut off for some reason. Here is my output before using toupper():
ciphertext: EHBBQ
And here is my output after I use toupper():
ciphertext: EHBB
Here is my code:
int main(int argc, string argv[]) {
string plaintext = get_string("plaintext: ");
// Putting all the argv letters into an array called key
char key[26]; // change 4 to 26
for (int i = 0; i < 26; i++) // change 4 to 26
{
key[i] = argv[1][i];
}
// Assigning array called ciphertext, the length of the inputted text, to hold cipertext chars
char ciphertext[strlen(plaintext)];
// Looping through the inputted text, checking for upper and lower case letters
for (int i = 0; i < strlen(plaintext); i++)
{
// The letter is lower case
if (islower(plaintext[i]) != 0)
{
int asciiVal = plaintext[i] - 97; // Converting from ascii to decimal value and getting it into alphabetical index (0-25)
char l = tolower(key[asciiVal]); // tolower() works properly
//printf("%c", l);
strncat(ciphertext, &l, 1); // Using strncat() to append the converted plaintext char to ciphertext
}
// The letter is uppercase
else if (isupper(plaintext[i]) != 0)
{
int asciiVal = plaintext[i] - 65; // Converting from ascii to decimal value and getting it into alphabetical index (0-25)
char u = toupper(key[asciiVal]); // For some reason having this cuts off the last letter
strncat(ciphertext, &u, 1); // Using strncat() to append the converted plaintext char to ciphertext
}
// If its a space, comma, apostrophe, etc...
else
{
strncat(ciphertext, &plaintext[i], 1);
}
}
// prints out ciphertext output
printf("ciphertext: ");
for (int i = 0; i < strlen(plaintext); i++)
{
printf("%c", ciphertext[i]);
}
printf("\n");
printf("%c\n", ciphertext[1]);
printf("%c\n", ciphertext[4]);
//printf("%s\n", ciphertext);
return 0;
}
The strncat function expects its first argument to be a null terminated string that it appends to. You're calling it with ciphertext while it is uninitialized. This means that you're reading unitialized memory, possibly reading past the end of the array, triggering undefined behavior.
You need to make ciphertext an empty string before you call strncat on it. Also, you need to add 1 to the size of this array to account for the terminating null byte on the completed string to prevent writing off the end of it.
char ciphertext[strlen(plaintext)+1];
ciphertext[0] = 0;
There are multiple problems in the code:
you do not test the command line argument presence and length
the array should be allocated with 1 extra byte for the null terminator and initialized as an empty string for strncat() to work properly.
instead of hard coding ASCII values such as 97 and 65, use character constants such as 'a' and 'A'
strncat() is overkill for your purpose. You could just write ciphertext[i] = l; instead of strncat(ciphertext, &l, 1)
islower() and isupper() are only defined for positive values of the type unsigned char and the special negative value EOF. You should cast char arguments as (unsigned char)c to avoid undefined behavior on non ASCII bytes on platforms where char happens to be a signed type.
avoid redundant tests such as islower(xxx) != 0. It is more idiomatic to just write if (islower(xxx))
Here is a modified version:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <cs50.h>
int main(int argc, string argv[]) {
// Testing the argument
if (argc < 2 || strlen(argv[1]) != 26) {
printf("invalid or missing argument\n");
return 1;
}
// Putting all the argv letters into an array called key
char key[26];
memcpy(key, argv[1], 26);
string plaintext = get_string("plaintext: ");
int len = strlen(plaintext);
// Define an array called ciphertext, the length of the inputted text, to hold ciphertext chars and a null terminator
char ciphertext[len + 1];
// Looping through the inputted text, checking for upper and lower case letters
for (int i = 0; i < len; i++) {
unsigned char c = plaintext[i];
if (islower(c)) { // The letter is lower case
int index = c - 'a'; // Converting from ascii to decimal value and getting it into alphabetical index (0-25)
ciphertext[i] = tolower((unsigned char)key[index]);
} else
if (isupper(c)) {
// The letter is uppercase
int index = c - 'A'; // Converting from ascii to decimal value and getting it into alphabetical index (0-25)
ciphertext[i] = toupper((unsigned char)key[index]);
} else {
// other characters are unchanged
ciphertext[i] = c;
}
}
ciphertext[len] = '\0'; // set the null terminator
printf("ciphertext: %s\n", ciphertext);
return 0;
}
I'm trying to write code that will take each digit from a plaintext string input and, if it is a letter, output a different letter, as defined by a substitution key (26-letter key).
In other words, if the alphabet was "abcd" and provided key was "hjkl", an input of "bad" would output "jhl".
// Regular alphabet is to be used as comparison base for key indexes //
string alphabet = "abcdefghijklmnopqrstuvwxyz";
// Prompt user for input and assign it to plaintext variable //
string plaintext = get_string("plaintext: ");
Non-letters should be printed as-is.
My idea was to loop the input digit through every index in the alphabet looking for the corresponding letter and, if found, print the same index character from the string. (confusing, I think)
This loop, however, returns a segfault when I run it, but not when debugging:
// Loop will iterate through every ith digit in plaintext and operate the cipher //
for (int i = 0; plaintext[i] != '\0'; i++) {
// Storing plaintext digit in n and converting char to string //
char n[2] = "";
n[0] = plaintext[i];
n[1] = '\0';
// If digit is alphabetic, operate cipher case-sensitive; if not, print as-is //
if (isalpha(n) != 0) {
for (int k = 0; alphabet[k] != '\0'; k++) {
char j[2] = "";
j[0] = alphabet[k];
j[1] = '\0';
if (n[0] == j[0] || n[0] == toupper(j[0])) {
if (islower(n) != 0) {
printf("%c", key[k]);
break;
} else {
printf("%c", key[k] + 32);
break;
}
}
}
} else {
printf("%c", (char) n);
}
}
What's going wrong? I've looked for help online but most sources are not very beginner-friendly.
Your code seems to be working except one error: The program crashes at
isalpha(n)
Cause you declared
char n[2]
the parameter there is a pointer of type char*. But islower only accepts an int parameter, so just write it as
isalpha(n[0])
Same for islower.
I am extremely new to programming and I'm having some difficulties with Vigenere in C from the edX course CS50. I have broken the problem down into uppercase letters and lowercase letters and I am only trying to solve the uppercase letter problem right now. I am using the word 'panda' as my key and 'ILIKEYOU' as the plaintext. When I run the program, the first letter corresponds to the letter I'd expect it to be (23=X). After that, the program just seems to spit out random numbers for the remaining 7 letters. I haven't converted back to ASCII since I'm having so many problems with my code. Any ideas what is going on? Thank you all so much for the help :)
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{
// Print error message if the user imput is executed without any
command-line arguments or with more than one command-line argument
if (argc != 2)
{
printf("Usage: ./vigenere k\n");
return 1;
}
// Access key
string key = argv[1];
// Convert the array from a string to an int
int letter;
letter = atoi(argv[1]);
// Print error message if the user imput is one command-line argument
and contains *any* non-alphabetical character(s)
for (int c = 0; c < strlen(key); c++)
{
if (!isalpha (key[c]))
{
printf("Usage: ./vigenere k\n");
return 1;
}
}
// Prompt the user for a string of plaintext
string p;
p = get_string("plaintext:");
//Print ciphertext
printf("ciphertext: ");
// Accessing each character in the plaintext
for (int i = 0, n = strlen(p); i < n; i++)
{
// Shift letters only in the plaintext
if (isalpha(p[i]))
{
// Convert plaintext and key to ASCII capital letters to
alphabetical index
// Encipher capital letters in plaintext and print
int c = 0;
if (isupper(p[i]))
{
printf("%i\n", ((p[i] - 65) + (toupper(key[c]) - 65)) % 26);
}
}
}
Needs few modifications -
int index_key = 0;
int shift= 0;
int key_len = strlen(key);
for (int i = 0, n = strlen(p); i < n; i++)
{
// Shift letters only in the plaintext
if (isalpha(p[i]))
{
// Convert plaintext and key to ASCII capital letters to
//alphabetical index
// Encipher capital letters in plaintext and print
if (isupper(p[i]))
{
shift = ((p[i] - 'A') + (toupper(key[index_key % key_len]) - 'A')) % 26;
index_key++;
printf("%c", p[i] + shift);
}
}
}
#include <stdio.h>
int main()
#include <stdio.h>
int main()
{
char msg[31] = {'\0'};
char encrypted[31] = {'\0'};
int key;
printf("Please enter a message under 30 characters: ");
fgets(msg, 31, stdin);
printf("Please enter an encryption key: ");
scanf("%d", &key);
int i = 0;
while (msg[i] && ('a' <= msg[i] <= 'z' || 'A' < msg[i] < 'Z'))
{
encrypted[i] = (msg[i] + key);
i++;
}
printf("%s\n", msg);
printf("%d\n", key);
printf("%s\n", encrypted);
}
Okay i've got my code to increment the characters but i don't know how to make it ignore special characters and spaces. Also how do i use % to loop back to 'a' and 'A'?
Thank you.
You just need a simple for loop:
for (int i = 0; i < 31; i++)
{
// operate on msg[i]
}
If you didn't know the length of the string to begin with, you might prefer a while loop that detects the null terminator:
int i = 0;
while (msg[i])
{
// operate on msg[i]
i++;
}
Your fgets and scanf are probably fine, but personally, I would be consistent when reading input, and fgets for it all. Then you can sscanf to get key out later.
scanf and fgets seem fine in this situation the way you've used them.
In C, a string is just an array of characters. So, you access each element using a for loop and array indexing:
for (int i = 0; i < strlen(str); i++) {
char thisChar = str[i];
//Do the processing for each character
}
You can perform arithmetic on thisChar as necessary, but be careful not to exceed 255. You might want to put a check on key to ensure it doesn't get too big.
Getting a string from scanf:
char msg[31];
scanf("%30s", msg);
OR (less efficient, because you have to fill the array with 0s first)
char msg[31] = { 0 };
scanf("%30c", msg);
Iterating a string is as easy a for loop (be sure to use c99 or c11)
int len = strlen(msg);
for(int i = 0; i < len; i++) {
char current = msg[i];
//do something
msg[i] = current;
}
"Encrypting" (i.e. ciphering) a character require a few steps
Determine if we have an uppercase character, lowercase character, or non-alphabetic character
Determine the position in the alphabet, if alphabetic.
Update the position, using the modulus operator (%)
Correct the position, if alphabetic
I could give you the code here, but then you wouldn't learn anything from doing it yourself. Instead, I encourage you to implement the cipher based on the steps I provided above.
Note that you can do things like:
char c = 'C';
char e = 'E' + 2;
char lower_c = 'C' - 'A' + 'a';