This is a Vigenere cypher for cs50. It's my first time coding and I'm going around this for a week now, and I don't seem to be able to print first letter after the loop finishes for the first time.
For example:
jharvard#appliance (~/Dropbox): ./viginere abcde
You're key is abcde
Type your text:
aaaaa aaaaaa aaaaaaa aaaaaaaa
abcde bcde bcdebc debcde
First a is printed but then it starts on b and in the end it doesn't print every letter. The key is chosen by the user.
I have no idea what I'm doing wrong.
for (int i = 0, j = strlen(plain_text), l = 0; i < j; i++)
{
int rotation_1 = (tolower(plain_text[i]) + (key[l] - 97)) % 122;
int rotation_2 = (plain_text[i] + (key[l] - 97)) % 122;
//if it is a letter
if (isalpha(plain_text[i]))
{
l = l % strlen(key);
//if the it is uppercase
if (isupper(plain_text[i]))
{
printf("%c", toupper(rotation_1));
}
//else if it is lowercase
else
{
printf("%c", rotation_2);
}
l++;
}
// if it is not a letter we print it as it is
else
{
printf("%c", plain_text[i]);
}
}
Here is a simpler version with the logic fixed:
for (int i = 0, n = strlen(plain_text), k = 0, klen = strlen(key); i < n; i++) {
int c = (unsigned char)plain_text[i];
//if it is a letter
if (isalpha(c)) {
if (isupper(c)) {
c = 'A' + (c - 'A' + key[k] - 'a') % 26;
} else {
c = 'a' + (c - 'a' + key[k] - 'a') % 26;
}
k = (k + 1) % klen;
}
putchar(c);
}
It is important to cast plain_text[i] as (unsigned char) because isalpha and isupper are only defined for all values of unsigned char and EOF. char may be signed by default of your platform.
Also note that putchar(c) is much more efficient than printf("%c", c);
Related
Stuck on this problem. Codes compiles, and takes input. however when attempting to use key '1' with plaintext 'a', i'm expecting 'b' but returning "\001" (which is not printing) when i check the debugger. Can someone help me explain why this is happening? I suspect error is when im allocating memory for the cypher test.. or when actually doing the cypher in my for / if statements.
int main(int argc,string argv[])
{
check_commands(argc);
//checks if key is alpha
string key = argv[1];
for (int i = 0; i < strlen(key); i++)
{
if (isalpha(key[i]))
{
printf("Usage: ./caesar key\n");
return 1;
}
}
//convert string argv[1] into an int
int k = atoi(key);
//ask user for pplaintect
string plaintext = get_string("Plaintext: ");
//create cyphertext variable
int s = strlen(plaintext);
char *cyphertext = malloc(s + 1);
printf("Cyphertext: ");
for (int i = 0; i < s; i++)
{
if (isalpha(plaintext[i]))
{
if (isupper(plaintext[i]))
{
// cypher based of k but keep upper
cyphertext[i] = ((plaintext[i] - 65) + k) % 26;
//print uppercase cypher
printf("%s", cyphertext);
}
if (islower(plaintext[i]))
{
//cypher based of k but keep lower
cyphertext[i] = ((plaintext[i] - 97) + k) % 26;
//print lowercase cypher
printf("%s", cyphertext);
}
}
else
{
printf("%c", plaintext[i]);
}
}
free(cyphertext);
printf("\n");
}
int check_commands(int argc)
{ //checks wether we have two command line arguments
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return 1; //error
}
return 0;
}
You're just putting the modulus into cyphertext. You need to add that to the first character of the alphabet to get the corresponding letter, just as you subtract the character before adding k.
cyphertext[i] = 'A' + ((plaintext[i] - 'A') + k) % 26;
Also, don't hard-code ASCII codes like 65 and 97. Use character literals.
You allocated an uninitialized memory
char *cyphertext = malloc(s + 1);
It does not contain a string. So you may not use the conversion specifier s in calls of printf like this
printf("%s", cyphertext);
Also in these statements
cyphertext[i] = ((plaintext[i] - 65) + k) % 26;
and
cyphertext[i] = ((plaintext[i] - 97) + k) % 26;
you are storing not printable alpha characters.
Also this record
int s = strlen(plaintext);
is redundant.
Use do-while loop instead of the for loop. For example
size_t i = 0;
do
{
if ( isupper( ( unsigned char )plaintext[i] ) )
{
// cypher based of k but keep upper
cyphertext[i] = 'A' + ( plaintext[i] - 'A' + k ) % 26;
}
else if ( islower( ( unsigned char )plaintext[i] ) )
{
//cypher based of k but keep lower
cyphertext[i] = 'a' + ( plaintext[i] - 'a' + k ) % 26;
}
else
{
cyphertext[i] = plaintext[i];
}
} while ( plaintext[i++] != '\0' );
puts( cyphertext );
free( cyphertext );
I'm trying to do the CS50 Vigenere exercise.
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, string argv[])
{
//Check for 2 command line arguments
if (argc != 2)
{
printf("Nah bro, you gotta have 2 arguments.\n");
return 1;
}
//Check is alpha
else {
for (int i = 0; i < strlen(argv[1]); i++)
{
if (isalpha(argv[1][i]) == 0)
{
printf("Nah bro, u gots to use letters.\n");
return 1;
}
}
}
//Prompt user to input text
printf("plaintext: ");
string p = get_string();
//Cipher
printf("ciphertext: ");
string k = argv[1];
int cipherlen = strlen(k);
//Cycle through key letters
for (int i = 0, j = 0, n = strlen(p); i < n; i++)
{
if (isalpha(p[i]))
{
if (isupper(p[i]))
{
printf("%c", ((p[i] - 65) + (k[(j % cipherlen)]) - 65) % 26 + 65);
j++;
}
else if (islower(p[i]))
{
printf("%c", ((p[i] - 97) + (k[(j % cipherlen)]) - 97) % 26 + 97);
j++;
}
else
printf ("%c", p[i]);
}
}
printf("\n");
return 0;
}
Here are my error codes according to the check:
https://cs50.me/checks/a56bc9325327035cb0e8d831693c9805c4b6468b
I understand my problem has to do with cycling through each letter but not applying it to spaces or symbols. I've tried using an if (isalpha) statement and an else printf(" ") but it doesn't work well for numbers or symbols. I figured adding j++ would iterate only through alpha characters but it doesn't seem to help.
Is there something here super plain I'm missing?
The basic structure of your code looks OK.
I see three problems with it:
All of your printfs are guarded by the if (isalpha(p[i])) check, so your program never outputs anything if the plaintext character is not alphabetic (it should output the character unchanged instead). The fix for this is simple; just remove the outer if (...) in the loop:
for (int i = 0, j = 0, n = strlen(p); i < n; i++)
{
if (isupper(p[i]))
{
printf("%c", ((p[i] - 65) + (k[(j % cipherlen)]) - 65) % 26 + 65);
j++;
}
else if (islower(p[i]))
{
printf("%c", ((p[i] - 97) + (k[(j % cipherlen)]) - 97) % 26 + 97);
j++;
}
else
printf ("%c", p[i]);
}
The inner if/else if chain handles this case correctly.
The current plaintext character p[i] and the current keyword character k[j % cipherlen] can be uppercase / lowercase independently. Your code currently does not handle this at all; instead it assumes that if p[i] is uppercase, k[j % cipherlen] must be uppercase as well, and similarly for lowercase.
By the way, I recommend against writing 65 and 97 in the code. I'd use 'A' and 'a' instead, respectively, which makes things more readable IMHO.
To fix this issue, you have to test k[j % cipherlen] for uppercase / lowercase separately. For example:
for (int i = 0, j = 0, n = strlen(p); i < n; i++)
{
char key_char = k[j % cipherlen];
int key_shift;
if (isupper(key_char)) {
key_shift = key_char - 'A';
} else {
key_shift = key_char - 'a';
}
if (isupper(p[i]))
{
printf("%c", ((p[i] - 'A') + key_shift) % 26 + 'A');
j++;
}
else if (islower(p[i]))
{
printf("%c", ((p[i] - 'a') + key_shift) % 26 + 'a');
j++;
}
else
printf ("%c", p[i]);
}
(I got tired of repeatedly typing the same expressions, so I extracted the common bits out to variables (key_char, key_shift). The only tricky part here is that j should only be incremented if key_shift is actually used, but your code already handles that.)
This is a subtle point, but all the <ctype.h> functions (such as isupper, isalpha, ...) have undefined behavior if the argument is negative. char is a signed type in many implementations, so a random character str[i] may well be negative. To be completely portable and correct, you should cast the character to (unsigned char) in each such call:
if (isupper((unsigned char)key_char))
...
if (isupper((unsigned char)p[i]))
...
else if (islower((unsigned char)p[i]))
...
Alternatively, just fully embrace ASCII (the rest of your code assumes it already) and do:
if (key_char >= 'A' && key_char <= 'Z')
...
if (p[i] >= 'A' && p[i] <= 'Z')
...
else if (p[i] >= 'a' && p[i] <= 'z')
...
I am doing a problem set from the CS50 course and we have to implement Caesar's cipher. The following code works only with numbers (they remain the same as intended), when you put in a character, however, nothing is output. What's wrong?
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
//problem set requires arguments
int main (int argc, string argv [])
{
int i = 0;
if (argc != 2){
printf ("Retry\n");
return 1;
} else {
int x = atoi(argv [1]);
//gets plaintext
string a = get_string ("plaintext:");
printf("ciphertext:");
for (i = 0; i <= strlen(a); i++){
//if character is a number it remains unchanged
if (isdigit(a[i])){
printf ("%c", a[i]);
} else {
if (isupper(a[i])){
//converts from ASCII index to alphabetical index
char y = a[i] - 65;
//Caesar cipher formula. If upper case remains upper case.
y = toupper(a[i] + x % 26);
//goes back ASCII
printf("%c", y + 65);
} else if (islower(a[i])){
//converts from ASCII index to alphabetical index
char t = a[i] - 65;
//Caesar cipher formula. If lower case remains lower case.
t = tolower(a[i] + x % 26);
//goes back to ASCII
printf("%c", t + 65);
}
}
}
}
}
65 is the ASCII value for letter 'A'. If you are working on lower case word, you would need 97, which is ASCII value for 'a'
You have calculated t, but you didn't carry the result to the next line. Moreover, you have to take the modulus on the whole line. You are expecting that t is between 0 and 26, then you add it to 97
char t = a[i] - 97;
t = (t + x) % 26;
printf("%c", t + 97);
Also the for loop should go up to strlen(a). The last index in the string a is null-character, it should not be modified. You can also use 'a' instead of 97 here.
for(i = 0; i < strlen(a); i++)
{
if(isupper(a[i]))
{
char y = a[i] - 'A';
y = (y + x ) % 26;
printf("%c", y + 'A');
}
else if(islower(a[i]))
{
char t = a[i] - 'a';
t = (t + x )% 26;
printf("%c", t + 'a');
}
else
{
printf("%c", a[i]);
}
}
First of all there is no one that I can ask this kind of question so please pardon me
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[]) {
string key = argv[1];
int l = strlen(argv[1]);
if (argc != 2) {
return 0;
}
for (int i = 0, n = strlen(key); i < n; i++) {
if (!isalpha(key[i])) {
return 0;
}
key[i] = tolower(key[i]);
key[i] = key[i] - 97;
}
string txt = GetString();
for (int k = 0, p = strlen(txt); k < p; k++) {
if (isalpha(txt[k])) {
if (isupper(txt[k])) {
printf("%c", (((txt[k] - 65) + (key[k % l])) % 26 + 65));
}
if (islower(txt[k])) {
printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97));
}
} else
if (!isalpha(txt[k])) {
printf("%c", txt[k]);
}
}
printf("\n");
return 0;
}
I can't quite get these 2 lines of code
key[i] = key[i] - 97;
printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97));
Is there an easy explanation of why did we use the first and how the second one works?
The key used for the Vigenere cypher is supposed to be all letters. The first expression converts the string into an array of offsets, 0 for a, 1 for b, etc. 97 is the ASCII code for 'a'. It would be more readable to write:
for (int i = 0, n = strlen(key); i < n; i++) {
if (!isalpha((unsigned char)key[i])) {
printf("key '%s' must contain only letters\n", key);
return 1;
}
key[i] = tolower((unsigned char)key[i]);
key[i] = key[i] - 'a';
}
For the second expression, if the character txt[k] is a lower case letter, printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97)); computes and prints the transposed letter by adding the shift value (each character in key is used as a shift value one after the other, shifting by 0 for a, 1 for b etc.). Here are the steps:
The program computes the letter index txt[k] - 97, 97 being the ASCII code for 'a',
it then adds the shift value key[k % l], cycling the values in key in a circular fashion,
it takes the modulo 26 to get a letter index between 0 and 25.
it finally adds 97, the ASCII value of 'a' to convert the index back into a lowercase letter.
It would be less redundant and more readable to write it this way:
for (int i = 0, j = 0; txt[i] != '\0'; i++) {
int c = (unsigned char)txt[i];
if (isupper(c)) {
c = (c - 'A' + key[j++ % l]) % 26 + 'A';
} else
if (islower(c)) {
c = (c - 'a' + key[j++ % l]) % 26 + 'a';
}
putchar(c);
}
Also note that argv[1] should not be passed to strlen() before checking that enough arguments have been passed on the command line.
Here is a modified version of the program:
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, string argv[]) {
if (argc != 2) {
printf("missing key argument\n");
return 1;
}
string key = argv[1];
int klen = strlen(key);
if (klen == 0) {
printf("key cannot be empty\n");
return 1;
}
for (int i = 0; i < klen; i++) {
if (!isalpha((unsigned char)key[i])) {
printf("key '%s' must contain only letters\n", key);
return 1;
}
key[i] = tolower((unsigned char)key[i]) - 'a';
}
string txt = GetString();
for (int i = 0, j = 0; txt[i] != '\0'; i++) {
int c = (unsigned char)txt[i];
if (isupper(c)) {
c = (c - 'A' + key[j++ % klen]) % 26 + 'A';
} else
if (islower(c)) {
c = (c - 'a' + key[j++ % klen]) % 26 + 'a';
}
putchar(c);
}
putchar('\n');
return 0;
}
key[i] = key[i] - 97;
That line's use is to give key[i], which value represents the value of a caracter in ascii it's index in our alphabet. Then, 'a' will be given the value 0, 'b' the value 1 .... , and 'z' the value 25.
As for the second line,
printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97))
it prints the caracter which's ascii value is
(((txt[k] - 97) + (key[k % l])) % 26 + 97))
The substraction of 97 has the same purpose as explained above.
The % 26 is the modulus, ie the remainder of ((txt[k] - 97) + (key[k % l])) when divided per 26 (integer division). Then, 97 is added again to convert the order, or index of the result into a corresponding ascii value.
This page might give you some more insight about the character representation in C.
As for the meaning of k,i and l, I let you grasp the inner functionning of the cypher by yourself, but the whole encryption happens in the second line you wished an explanation for.
PS : The parts with '65' are just the same, but with uppercase letters, since 'A' value in ascii is 65.
I am stuck in this example. Whenever I put the keyword 'bacon' I get the wrong answer.
Any idea why this is happening? I can't find the bug and I have tried a lot.
Can you please help me?
When I run this: ./vigenere bacon and input the text Meet me at the park at eleven am the answer should be Negh zf av huf pcfx bt gzrwep oz, but instead I get Negh ne og tjs qaty bt syfvgb bm
Update: I made some changes as suggested by the comments but still having the same problem.
#include<cs50.h>
#include<ctype.h>
#include<stdio.h>
#include<string.h>
int main(int argc, char *argv[])
{
//check if it has only two values
if (argc != 2)
{
printf("Usage: ./vigenere keyword\n");
return 1;
}
// check that every letter of keyword is alphabetic
char *keyword = argv[1];
int keylen = strlen(keyword);
for (int i = 0, n = keylen; i < n; i++)
{
if(!isalpha(keyword[i]))
{
printf("alphabetic keyword only!!!\n");
return 1;
}
if(isalpha(keyword[i]))
{
// if a letter of keyword is uppercase
if (isupper(keyword[i]))
{
keyword[i] = keyword[i] - 'A';
}
// if a letter of keyword is lowercase
if (islower(keyword[i]))
{
keyword[i] = keyword[i] - 'a';
}
}
}
char *text = GetString();
for (int i = 0, n = strlen(text); i < n; i++)
{
if (isalpha(text[i]))
{
// if plaintext letter uppercase then...
if (isupper(text[i]))
{
text[i] = ((text[i] - 'A') + (keyword[i % keylen])) % 26 + 'A';
printf("%c",text[i]);
// ^^^^^^ ----> repeat the pattern
}
// if plaintext letter lowercase then ...
if (islower(text[i]))
{
text[i] = ((text[i] - 'a') + (keyword[i % keylen])) % 26 + 'a';
printf("%c",text[i]);
}
}
// if no letters in plaintext then ...
if (!isalpha(text[i]))
{
text[i] = text[i];
printf("%c",text[i]);
}
}
printf("\n");
}
So as #BLUEPIXY suggested I had to use a different variable in order to get the right answer:
`char *text = GetString();
int k = 0;
for (int i = 0, n = strlen(text); i < n; i++)
{
if (isalpha(text[i]))
{
// if plaintext letter uppercase
if (isupper(text[i]))
{
text[i]= ((text[i] - 'A') + (keyword[k % keylen])) % 26 + 'A';
printf("%c",text[i]);
//^^^^^ ----> repeat the keyword pattern
}
// if plaintext letter lowercase
if (islower(text[i]))
{
text[i] = ((text[i] - 'a') + (keyword[k % keylen])) % 26 + 'a';
printf("%c",text[i]);
}
k++;
}`