I am having a terrible time understanding how to get the wrapper to work with these encryption programs. I got a Caesar cipher program to work to both encrypt and decrypt, now I am working on a Vigenere cipher. I have the program working but when I use a key that will cause the letters to wrap around I get odd results. Here is the code I am using:
int main(int argc, char *argv[])
{
char s2[25];
strcpy(s2, argv[1]);
printf("Please enter a string of text to be encrypted!\n");
string p = GetString();
for (int i = 0, n = strlen(p); i < n; i++)
{
if (isupper(p[i])){
char c = (p[i] - 'A' + s2[i]);
printf("%c", c);
}
}
printf("\n");
}
This code will work if the command line input is ./program BACON and I enter BLAH for the text to be encrypted. If for example I use ./program ZZZZZ as the key then I will get all kinds of odd results because it does not wrap back around. I have tried using the modulus operator and have left it out of the code I just posted because I still could not get it to wrap with that. I am just starting to learn programming.
Update
Maybe you can help me understand the math better; your code works perfectly, but I have been trying to figure this out on a calculator manually just to see what's going on. This is what I have so far:
./program HHHHH
keyLen should equal 5 in my understanding and so if I give p[i] a value of "H"
keyLen= 5
p[i]= H //or 72 in ASCII
int sum = (p[i] - 'A') + (s2[i % keyLen] - 'A'); //sum = (72 - '65') + ([72 % 5] - '65');
char c = 'A' + sum%26; // c = 65 + -11
Maybe my math is way off because when I do things in the order I think they should be done sum = negative 63 and so a 26 mod of -63 which gives me negative 11. Which clearly is not right because that equals 54 when you add 65 and negative 11.
Even if I make the negative 11 a positive integer of 11 and add 65 I get 76 which is ASCII character "L" but the right answer is "O". I am clearly doing something wrong but I've been working on the solution for a while now and keep coming up with the same results.
There are two "wrap-around" issues in your program:
Your letters do not wrap around when the key and the current letter combine to produce a value beyond 26, and
You read past the end of the key when the length of the word being encrypted exceeds the length of the key.
Here is how you fix it: right after copying the key into s2, do this:
int keyLen = strlen(s2);
Now inside your loop do this:
int sum = (p[i] - 'A') + (s2[i % keyLen] - 'A'); // Calculate the sum of key+word
char c = 'A' + sum%26; // Wrap around at 26, the number of letters in the alphabet
This will make the output look "normal".
Once you figure out how the last formula works, you should be able to modify it to decode the word.
Related
Task:
Create a function maxRepeatingLetter that receives a string and as a result returns the letter that is repeated the most times in the given string (if more than one letter meets the given condition, return the first letter of the English alphabet). It is assumed that there will be at least one letter in the string.
Code:
#include <stdio.h>
char maxRepeatingLetter(const char *s)
{
int i, max = 0, maxIndex = 0;
int letter[26] = {0};
const char *pom = s;
while (*pom != '\0')
{
if ((*pom >= 'a' && *pom <= 'z'))
{
letter[*pom - 97]++;
}
if (*pom >= 'A' && *pom <= 'Z')
{
letter[*pom - 65]++;
}
pom++;
}
for (i = 0; i < 26; i++)
{
if (letter[i] > max)
{
max =letter[i]; maxIndex = I;
}
return maxIndex + 65;
}
int main ()
{
printf("Most repeating letter is: %c",
maxRepeatingLetter("input for letter to repeat"));
return 0;
}
My current task is being able to explain the code above and how it works. And I need to input a minor change into it, for example, to add something to the code, or make it simpler. But not to lose the main functions the code has.
Is anyone willing to explain the code above in 2-3 lines? And if you could, assist me or hint me, or even show me, what changes to the code I could apply.
I can see that you have to distinguish lowercase and uppercase and you can have only letters not symbols such as ? | ^ ! ecc... so I'll try to give you some advice:
Try to indent the code, it will be more readable to an external eye.
Using the variable letter is a good idea but i don't get the point of using pom.
If you can use use the function strlen() from the library string.h, otherwise implementing it by yourself could be a good exercise.
letter[*pom - 97]++, letter[*pom - 65]++ and maxIndex + 65 are dependant from the ASCII table, try letter[*pom - 'a']++, letter[*pom - 'A']++ and maxIndex + 'A'.
The for loop doesn't work, you missed a brackets so the if isn't in the for.
The code explanation is pretty easy, first of all you use the arrayletter of 26 elements because in the alphabet we have 26 letters, so the i-th element correspond to the i-th letter of the alphabet.
You loop once on the string and save in the i-th element letter the number of occurrence of the i-th letter.
With the if in for loop you are simply finding the max in that array, once found it, you return the index of the max, the index is the letter occuring more often.
Sorry for my bad English tell me if you need more help.
It is very straightforward if you are looking for an explanation of the above code. I recommend using multiple prints to understand how things are happening. Here are my few tips.
function maxRepeatingLetter() is updating the counter table letter[] each time the character appears.
After that, the code tries to find the highest number in the counter table letter[].
I have the following problem:
I would to implement a ceaser cipher which works mostly, but when I reach the end of the alphabet it goes beyond the alphabet which I assume is due to the ascii values.
for example:
if I insert a k and use the key 35 I get a H but it should wrap around in the lowercase letters and produce a b.
It also sometimes produces a punctuation mark or something else like < which I do not want.
The code responsible for the encryption is
encripted_text = (plain_text + key - 97)%26 +97;
am I missing something to make it wrap around and only stay in the alphabet.
Example run of program:
char plain_text = 'k';
int k = 35;
char encripted_text = '\0';
encripted_text = (plain_text + key - 97)%26 + 97;
printf("%c", encripted_text);
Thanks for your help.
Assuming that encripted_text and plain_text are both char variables (1 byte), you have to decide a formula making sure that even when the result wraps around a valid output character is calculated.
How to do that? It depends on what are valid chars for you! In some cases you can simply rely on how characters are mapped in ASCII code, but I want suggest you a general solution that you will be able to translate in your specific requirement.
This general solution consists in defining an array with the accepted alphabet, and translate the input character to one of the characters in it.
For example:
char alphabet[] = { 'a','A','b','B','c','C' }; //just an example
char input_char = 'k';
int key = 35;
char encripted_char = '\0';
encripted_char = alphabet[(input_char + key - 97)%(sizeof(alphabet))];
printf("%c", encripted_char );
Summarizing: the formula doesn't calculate directly the encrypted char, but the index of the accepted alphabet array normalized using % operator.
I got the right output with the same logic #nad34. In fact, I correctly got the output as 't' for 'k'. It shouldn't and won't give a 'b'.
Your code is having the right logic, except for a few slight errors.
I don't know why you're using a string here, but since you are anyway, this -> char plain_text[] = 'k'; should instead be char plain_text[] = "k"; ==> Note the double quotes.
int k = 35; should be int key = 35;, since you have used the variable name key and not k.
Logicwise it is right, and it will give you the right output.
You can check out the execution of the same code here.
In the CS50 2019 Caesar assignment, I am supposed to perform Caesar shifts on characters by a given number of letters (key).
To do this, I add the value of key to each letter, as such:
for each character in plaintext:
plaintext[character] += key
Since I want z to loop back to a, I then wrote:
while (ciphered_character > 122)
{
ciphered_character -= 26;
}
Running the program with plaintext of z and a key of 26 causes 26 to be added to z (which is represented by 122). This causes plaintext[character] to overflow (past 127, I presume) and become negative before the while loop even kicks in. This gives a garbage output.
I know I can check for potential overflows beforehand and subtract 26 first, but that complicates my code. Can I give the variable 'more room' to prevent it from overflowing?
Do I use a different data type? What is the best practice here?
If you only care about lower case then this will work for you:
for each character in plaintext:
plaintext[character] = (plaintext[character] - 'a' + key) % 26 + 'a'
Subtracting 'a' to give you a value of 0-25, then add the key. If there is a overflow the modulo will give you the updated value in the 0-25 range which is added back to 'a' to get the correct character.
If you do need to handle both upper and lower case then you will need two different cases - one using 'a' and the other using 'A'. Select the the correct case for each character by checking isupper(plaintext[character])
Fun project;
I did it like this, assuming ASCII and using the full range of printable characters, from Space to ~
void caeser_shift(char* text, int key)
{ while (*text) { *text++ = ((*text-' ') + key) %('~'-' ') + ' '; } }
int main(void)
{
char plaintext[] = "Hello World; This is a test.";
caeser_shift(plaintext, 26);
printf("%s\n", plaintext);
return 0;
}
Output
Success #stdin #stdout 0s 4520KB
b!((+:q+.( U:n$%/:%/:{:0!/0H
My problem is that i dont know what this functions do, thats program
from my teacher(not whole program just functions). Just wanna ask you what this functions do, mainly why
i store my number from right to left at string? thanks
#include<stdio.h>
#include<string.h>
#define MAX 1000
void str_to_num(char *str, char *number, int *dlzka)
{
int i;
for(i=0; i < MAX; i++)
number[i] = 0;
*dlzka = strlen(str);
for(i = 0; i < *dlzka; i++)
cis[(*dlzka) - 1 - i] = str[i] - '0';
}
void plus(char *cislo, int *d1, char *cis2, int d2)
{
int i; prenos = 0;
if(*d1 < d2)
*d1 = d2;
for(i = 0; i < *d1; i++)
{
pom = number[i] + number[i];
pom += prenos;
number[i] = pom % 10;
prenos = pom / 10;
}
}
Here is the lesson your teacher should be teaching:
There is a difference between the numerical value of 1, and the computer code (ASCII for example) that is used to represent character 1 displayed on the screen or typed on the keyboard.
Every time you see 1 on the screen, your computer sees 49 in memory.
0 is 48, 2 is 50 and so on.
Conveniently, all digit characters are arranged in a sequence from 0 to 9, so to convert their character codes to their numeric values all you have to do is subtract the character code of zero to get the digit position in the sequence.
For example: 49 - 48 = 1 --> '1' - '0' = 1
And this is how the first function, str_to_num works.
C language does not provide a variable large enough to work with 100 digit numbers, so you need to sum them up one digit at a time.
The second function has completely wrong variable names, but it is still pretty obvious what it is trying to do:
It sums up two single digit numbers, then stores the ones part of the result in an array and the tenth (if sum is > 9) in a helper variable.
As already suggested in the comments, this is how you sum up numbers manually on a page one digit at a time.
I don't know what prenos means in your language, but in English this variable should be called carry and it keeps the overflowing tens digit for the next round.
There is however something missing from the sum function: if the sum of the last (leftmost) two digits is more than 9, the extra 1 will be lost, and the result will be wrong.
Check the original code your teacher gave you - either you copied it wrong, or he is giving a bad example.
I am taking Harvard's CS50 course through EDX (just for myself, this is not graded work). My Vigenere cipher from PSET2 is giving the wrong output - for example, both a key and an input of a should result in an output of a, but instead gives t. However, I can't pinpoint where the problem is.
#import <stdio.h>
#import <cs50.h>
#import <string.h>
#import <ctype.h>
int main(int argc, char *argv[])
{
//Variables
string key;
key = argv[1];
string plainText;
plainText = argv[2];
int i;
int k;
i = 0;
k = 0;
//Encrypt the string
for (i = 0; i < strlen(plainText); i++)
{
if (isalpha(plainText[i]))
{
if (islower(plainText[i]))
{
printf("%c",plainText[i] - 97 + key[k] % 26 + 97);
k++;
}
if (isupper(plainText[i]))
{
printf("%c",plainText[i] - 65 + key[k] % 26 + 65);
k++;
}
}
else
printf("%c",plainText[i]);
}
printf("\n");
}
If the values of the key array are supposed to represent the cyclic shift value (with aA standing for zero shift, bB - shift of 1 and so on) then the encoding expression should look as follows
(plainText[i] - 97 + key[k] - 97) % 26 + 97
Of course, in that case you have to independently take into account the case of key[k] character as well (and subtract either 97 or 65 from key[k]), which you ignore completely at this time.
Well, I can't provide a complete answer because I'm also struggling with this one. However, a couple of things I noticed from your code was that your plainText is argv[2] but there should only be 2 arguments passed through command line (argv[0] (the name of the program) and argv[1] (the users key)). For the plainText you should use GetString() from the cs50 library.
The other thing I noticed was that although you use the key[k] in your printf(), you aren't iterating through it in the loop. I am also having difficulty with this part. So, unfortunately I can't be certain of this part. I think you probably need a loop to go through each letter of the key in order to make a/A = 0 and z/Z = 25.
Don't forget that your key[] letter values start at 97 (for lowercase) or 65 (for uppercase) - you need to adjust them for the mod 26 operation to make sense.
And keep in mind that the mod operator (%) has a higher precedence than addition and subtraction; you might need to use parens to have it apply to the correct sub-expression.
I haven't looked at the requirements of the assignment, so I'm not sure if the program is expected to handle the possibility of key characters being uppercase or lowercase (or even non-alpha), if so you will need to add some logic to handle that complexity. Also, the way the program is coded right now, if your key is shorter than the plaintext you'll have problems - I assume your code is expected to handle 'wrapping' the key as necessary.