Instantly share code, notes, and snippets.

# CraigRodrigues/caesar.c Last active Sep 29, 2019

My solution to CS50 pset2 - "Hail, Caesar!"
 #include #include #include #include /** * Caesar.c * A program that encrypts messages using Caesar’s cipher. Your program must * accept a single command-line argument: a non-negative integer. Let’s call it * k for the sake of discussion. If your program is executed without any * command-line arguments or with more than one command-line argument, your * program should yell at the user and return a value of 1. * * */ int main(int argc, string argv[]) { // check for 2 arguments only if (argc != 2) { printf("Nope\n"); return 1; } // once I check for correct argv put key into an int k int k = atoi(argv); // check if the integer is non-negative if (k < 0) { printf("Nope\n"); return 1; } else { // prompt user for a code to encrypt string code = GetString(); for (int i = 0, n = strlen(code); i < n; i++) { //check if the letter is uppercase or lowercase then convert if islower(code[i]) printf("%c", (((code[i] + k) - 97) % 26) + 97); else if isupper(code[i]) printf("%c", (((code[i] + k) - 65) % 26) + 65); //if neither then just print whatever it is else printf("%c", code[i]); } printf("\n"); return 0; } }
Owner Author

### CraigRodrigues commented May 31, 2016 • edited

 Steps: Get a single command-line argument "key" from the user that is a non-negative integer. If not a single argument then yell at user. Take the "key" and turn it into an int with atoi since it starts as a string. Prompt user for a code they want to encrypt. Need to loop through the entire code letter by letter. Check if each letter is either lowercase, uppercase or neither. Standardize the ASCII value of the char to 26 then add the key. Then convert back into ASCII so that the code can wrap around properly. If neither a lowercase or uppercase letter then just print whatever the char is. This allows for spaces or special characters like ! or &. Once all of the above is complete print a new line. Return 0. Notes: Checking if the argv was a non-negative integer (don't think I even needed to do this). Figuring out how to standardize ASCII to the regular alphabet then converting back took a lot of time. This ASCII chart was incredibly useful - http://www.kerryr.net/pioneers/ascii3.htm Trying to put argv into a variable before I check if there is even an argv caused a segmentation fault. Didn't notice that toupper/tolower already checks if the character is a letter. First I had two more checks to see if the character was a letter or not when that wasn't necessary. ctype.h library is very useful - https://cs50.harvard.edu/resources/cppreference.com/stdstring/all.html

### drum35 commented Jul 7, 2017

 I love the elegance of your math!! I'm going through the class too and went about it the idiot way: `````` printf("plaintext: "); string message = get_string(); printf("ciphertext: "); for (int i = 0, n = strlen(message); i < n; i++) { int ci = message[i]; int wrapcheck = ci + key; if (ci > 64 && ci < 91 && wrapcheck < 91) { ci = wrapcheck; printf("%c", ci); } else if (ci > 64 && ci < 91 && wrapcheck > 90) { int dif = key % 26; ci = ci + dif; if (ci > 122) { ci = ci - 26; printf("%c", ci); } else printf("%c", ci); } else if (ci > 96 && ci < 123 && wrapcheck < 123) { ci = wrapcheck; printf("%c", ci); } else if (ci > 96 && ci < 123 && wrapcheck > 122) { int dif = key % 26; ci = ci + dif; if (ci > 122) { ci = ci - 26; printf("%c", ci); } else printf("%c", ci); } else { printf("%c", ci); } } } else { printf("ERROR: one command line argument only please!\n"); return 1; } printf("\n"); ``````

### teebl commented Jul 20, 2017

 Thanks for the code! Helped me understand the numbers game with the uppercase and lowercase characters!

### meetyourhomie commented Aug 3, 2017

 Hey why haven't you performed this step? string k = argv;

### valkukatov commented Sep 21, 2017

 @meetyourhomie argv[] takes input as a string even if an integer was provided, so he did an `int k = argv` instead, since that's the number that ascii alphabet will be incremented by.

### thegnord commented Nov 24, 2017 • edited

 I love it! (((code[i] + k) - 97) % 26) + 97); ...or 65 for uppercase... ^^^ This is very elegant and nice. At first I didn't understand how this could work for very large keys (1,000, 10,000, etc.), but after reading this post... https://stackoverflow.com/questions/2664301/how-does-modulus-divison-work ...I think I truly understand how modulo can be such an easy, elegant solution to problems like this. If someone reading this still doesn't understand, think of it this way: code[i] + k = add the key, even an extremely large one -97 (or 65 for uppercase) = subtract the "base." This brings the modified value down to a "base" of 0, effectively removing any part of the ASCII system that doesn't apply. It makes the letter "a" or "A" start at 1. Now mod by 26. The math here automatically wraps around as many times as required, only returning the "remainder," or offset from the base (which is now 0 thanks to step #2) +97 (or 65 for uppercase) = add the "base" back in so that the value can be output correctly in ASCII. Thanks for the post, I was struggling with this problem but hopefully I learned well.

### snekops commented Nov 30, 2017

 @thegnord thanks for your explanation! I also was struggling with this seemingly basic operation. Remove base, do stuff, add base back makes perfect sense but I completely blanked on that. <3

### Rubertavio commented Mar 26, 2018 • edited

 Hello! I already made this code on base of yours but I still can´t find the output called ciphertext. Are your code incomplete? Thanks!

### Vickoboy commented May 8, 2018

 let someone help me at this: Connecting....... Authenticating...... Preparing............... Uploading............. Checking....... :) caesar.c exists. :( caesar.c compiles. expected exit code 0, not 1 :| encrypts "a" as "b" using 1 as key can't check until a frown turns upside down :| encrypts "barfoo" as "yxocll" using 23 as key can't check until a frown turns upside down :| encrypts "BARFOO" as "EDUIRR" using 3 as key can't check until a frown turns upside down :| encrypts "BaRFoo" as "FeVJss" using 4 as key can't check until a frown turns upside down :| encrypts "barfoo" as "onesbb" using 65 as key can't check until a frown turns upside down :| encrypts "world, say hello!" as "iadxp, emk tqxxa!" using 12 as key can't check until a frown turns upside down :| handles lack of argv can't check until a frown turns upside down

### Bshivanshu commented May 12, 2018

 WHO came up with this ingenious formula?? Please tell. I am gone MAD thinking how one could come up with this ingenious formula! I kinda feel disappointed of myself! Should I take CS?

### 1Romario commented Jun 16, 2018 • edited

 Hello. Your code is not protected from entering the codeword as a word (there must be a number)

### cat-lee commented Jun 24, 2018

 i had the same concept, thankyou very much

### cat-lee commented Jun 24, 2018

 #include #include #include #include int main(int argc, string argv[]) { // Check if correct # of arguments given if (argc != 2) { printf ("Wrong number of arguments. Please try again.\n"); `````` return 1; } // Convert input to int type int k = atoi(argv); // Get text to encode string p = get_string(); // Loop through text for (int i = 0, n = strlen(p); i < n; i++) { // Keep case of letter if (isupper(p[i])) { // Get modulo number and add to appropriate case printf("%c", 65 + (p[i] - 65 + k) % 26); } else if (islower(p[i])) { printf("%c", 97 + (p[i] - 97 + k) % 26); } else { // return unchanged printf("%c", p[i]); } } printf("\n"); return 0; `````` }

### simbazone commented Dec 29, 2018

 Thanks so much for the explanation. I don't understand why we have to start at 97 though, based on this ASCII chart: http://www.asciichart.com/ If the goal is to return to the base like @thegnord said, then shouldn't it return to NUL instead of a? Forgive my ignorance but I am totally lost at this.

### dsimanoliveira commented Jan 23, 2019

 Thank you so much. This helped me to understand some basic stuff I was stuck. I just have one doubt...you didn't "block" the user to type letters, did you? So if they enter with that the program would run normally... Or am I missing something?

### Gagan1498 commented Feb 9, 2019

 @thegnord Can someone tell me what's the use of subtracting 97 at first and then adding again because the work is same, the reminder will be same also.

### nateharper1 commented Feb 20, 2019

 Wouldn't an input such as 10x or 1x840v technically still work though? So the code has a bug.

### cmkoopman commented Mar 17, 2019

 Thank you very much for posting this. It really helped.

### katsuya245126 commented Apr 1, 2019 • edited

 Wow very elegant solution. I made mine more complicated than it needed to be `````` #include #include #include #include bool isDigit(string s); int main(int argc, string argv[]) { //checks if the user used the right syntax and if the user input a digit if(argc == 2 && isDigit(argv)) { //convert user input string into int int key = atoi(argv); //store user input into plaintext and make a new char array (string) with the same length as plaintext string plainText = get_string("plaintext: "); char cipherText[strlen(plainText)]; strcpy(cipherText, plainText); //making cipher text from plain text here for(int i = 0; i < strlen(cipherText); i++) { //making sure to only change the alphabets, not the special characters if((cipherText[i] >= 'a' && cipherText[i] <= 'z') || (cipherText[i] >= 'A' && cipherText[i] <= 'Z')){ if ((cipherText[i] >= 'a' && cipherText[i] <= 'z')) { cipherText[i] = (cipherText[i] + key) % 122; if(cipherText[i] < 97) { cipherText[i] = (cipherText[i] % 26) + 96; } } else if ((cipherText[i] >= 'A' && cipherText[i] <= 'Z')) { cipherText[i] = (cipherText[i] + key) % 90; if(cipherText[i] < 65) { cipherText[i] = (cipherText[i] % 26) + 64; } } } } printf("ciphertext: %s\n", cipherText); return 0; } else { printf("Usage: ./caesar key\n"); return 1; } } //this function checks if the string is a decimal digit bool isDigit(string s) { for(int i = 0; i < strlen(s); i++) { //checks if the character is between 0-9 and returns false if it's not if(!(s[i] >= '0' && s[i] <= '9')) { return false; } } return true; } ``````

### goalmada commented Apr 3, 2019

 Hi everyone, How do we check for: \$ ./caesar 20x Usage: ./caesar key ?

### AbeerHaroon commented Apr 13, 2019

 Wow, so smart! Thank you very much, I've been stuck in this problem for so long

### p69d commented Apr 18, 2019

 @goalmada ``````#include string digits = argv; int i = 0; while (digits[i] != '\0') { // Validating the Key is number. if (!isdigit(digits[i])) { printf("Usage: ./caesar key\n"); return 1; } i++; } ``````

### Naiftt commented May 30, 2019

 I have solved it with basically the same style you made, but your code won't work if you enter a letter because it will read it as 0, and the program won't end. and it will approach it as if the key entered was 0

### yuriechan commented Jul 23, 2019

 While `code[i]` is a data type of string, why is this being used with other numerical values as follows? `(((code[i] + k) - 97) % 26) + 97)` Is `code[i]` automatically converted into an integer?

### yuriechan commented Jul 23, 2019

 Also, If we want to get alphabetical index, can we just substitute the base, and finish? Why do we have to substitute the base AND module by 26 to get the alphabetical index? For example, when the key is A = 65. Substitute by the base of the upper case, which is 65 minus 65 equals 0. Why do we have to do another `%26`, while this will only give the same number which is 0?

### gjgcorg1958 commented Aug 1, 2019

 While `code[i]` is a data type of string, why is this being used with other numerical values as follows? `(((code[i] + k) - 97) % 26) + 97)` Is `code[i]` automatically converted into an integer? According to the lesson, a string is a collection of char. code[i] is a char. When char is used in a arithmetic operations, it is converted to int.

### gjgcorg1958 commented Aug 1, 2019

 Also, If we want to get alphabetical index, can we just substitute the base, and finish? Why do we have to substitute the base AND module by 26 to get the alphabetical index? For example, when the key is A = 65. Substitute by the base of the upper case, which is 65 minus 65 equals 0. Why do we have to do another `%26`, while this will only give the same number which is 0? The modulo is part of the formula so you can loop back. the range of a-z is 97-122. if you increment by 1 and enter z the result will be 123 which is "[".