patterncMinor
Caesar Cipher that takes an arbitrary offset
Viewed 0 times
offsetarbitrarycaesarthattakescipher
Problem
This Caesar cipher can take any integer and it will wrap around the correct number of times and still perform the encryption/decryption.
Let's say we have a text file named
~$ cat dog
The quick brown fox jumps over the lazy dog...
If the user enters a normal offset (1-26), it will perform like any other Caesar cipher.
~$ ./caesar dog 1
~$ cat dog
Uif rvjdl cspxo gpy kvnqt pwfs uif mbaz eph...
Negative numbers can be used to shift backwards.
~$ ./caesar dog -1
~$ cat dog
The quick brown fox jumps over the lazy dog...
Now, here's the beauty of it. Choosing an offset of 1 is no different then choosing an offset of, say, 53 or -51. This algorithm will correctly wrap around.
~$ ./caesar dog -51
~$ cat dog
Uif rvjdl cspxo gpy kvnqt pwfs uif mbaz eph...
~$ ./caesar dog 51
~$ cat dog
The quick brown fox jumps over the lazy dog...
I wrote this a long time ago and I posted it on some other programming site back in the day. I haven't really written much pure
Compiles with:
```
#include
#include
#include
/ #define offset (-1) / / My chosen default offset /
#define lstart (0x61) / Start of lowercase ASCII alphabet /
#define ustart (0x41) / Start of uppercase ASCII alphabet /
#define nalpha 26 / Number of letters in my alphabet /
int main(int argc, char **argv) {
int ec, wrap, offset;
FILE *fp;
if (argc != 3) {
fprintf(stderr, "Usage: %s \n", argv[0]);
return 1;
}
fp = fopen(argv [1], "r+b");
offset = atoi (argv[2]);
if(!fp) {
fprintf(stderr, "Error: could not open file!\n");
return 1;
}
while((ec = fgetc(fp)) != EOF) {
if(isalpha(ec)) {
if(islower(ec)) {
wrap = (ec + offset - lstart) % nalpha;
wrap = (wrap < 0) ? nalpha + wrap : wrap;
Let's say we have a text file named
dog.~$ cat dog
The quick brown fox jumps over the lazy dog...
If the user enters a normal offset (1-26), it will perform like any other Caesar cipher.
~$ ./caesar dog 1
~$ cat dog
Uif rvjdl cspxo gpy kvnqt pwfs uif mbaz eph...
Negative numbers can be used to shift backwards.
~$ ./caesar dog -1
~$ cat dog
The quick brown fox jumps over the lazy dog...
Now, here's the beauty of it. Choosing an offset of 1 is no different then choosing an offset of, say, 53 or -51. This algorithm will correctly wrap around.
~$ ./caesar dog -51
~$ cat dog
Uif rvjdl cspxo gpy kvnqt pwfs uif mbaz eph...
~$ ./caesar dog 51
~$ cat dog
The quick brown fox jumps over the lazy dog...
I wrote this a long time ago and I posted it on some other programming site back in the day. I haven't really written much pure
c code since. I'm guessing there's plenty of room for improvement. Compiles with:
gcc -ansi -pedantic -Wall -Werror -O3 -o caesar caesar.c```
#include
#include
#include
/ #define offset (-1) / / My chosen default offset /
#define lstart (0x61) / Start of lowercase ASCII alphabet /
#define ustart (0x41) / Start of uppercase ASCII alphabet /
#define nalpha 26 / Number of letters in my alphabet /
int main(int argc, char **argv) {
int ec, wrap, offset;
FILE *fp;
if (argc != 3) {
fprintf(stderr, "Usage: %s \n", argv[0]);
return 1;
}
fp = fopen(argv [1], "r+b");
offset = atoi (argv[2]);
if(!fp) {
fprintf(stderr, "Error: could not open file!\n");
return 1;
}
while((ec = fgetc(fp)) != EOF) {
if(isalpha(ec)) {
if(islower(ec)) {
wrap = (ec + offset - lstart) % nalpha;
wrap = (wrap < 0) ? nalpha + wrap : wrap;
Solution
Some comments on your updated code in Rev 3:
-
I would define your constants as follows:
You now need no comments - they are obvious.
-
It would be normal to use
the file.
-
My man-page says
-
return values from main are traditionally
-
I would define
generally recommended not to define multiple variables on one line.
-
In the
is maintained. Equally, I would omit printing \n at the end so that the
output file (on stdout) has the same form as the input.
-
I prefer to see a space after keywords,
-
Don't overuse
-
I find a character named
maybe that is just me.
-
I think your encryption code:
would be better written:
-
I would define your constants as follows:
#define LSTART ('a')
#define USTART ('A')
#define NALPHA ('z' - 'a' + 1)You now need no comments - they are obvious.
-
It would be normal to use
perror(argv[1]); to print the error on openingthe file.
-
My man-page says
atoi has been depracated in favour of strtol-
return values from main are traditionally
EXIT_FAILURE and EXIT_SUCCESS-
I would define
offset and wrap at their point of first use. Also it isgenerally recommended not to define multiple variables on one line.
-
In the
while loop you should put the fputc(ec, stdout); outside theif(isalpha(ec)) {...} condition. That way the format of what you encryptis maintained. Equally, I would omit printing \n at the end so that the
output file (on stdout) has the same form as the input.
-
I prefer to see a space after keywords,
if, while etc. -
Don't overuse
?: - it is not a universal replacement for if-else-
I find a character named
ec to be less intuitive than one named ch, butmaybe that is just me.
-
I think your encryption code:
int ascii_offset = islower (ec) ? LSTART : USTART;
wrap = (ec + offset - ascii_offset) % NALPHA;
wrap = (wrap < 0) ? NALPHA + wrap : wrap;
ec = islower(ec) ? wrap + LSTART : wrap + USTART;would be better written:
const int ascii_offset = islower(ec) ? LSTART : USTART;
int wrap = (ec + offset - ascii_offset) % NALPHA;
if (wrap < 0) {
wrap += NALPHA;
}
ec = wrap + ascii_offset;Code Snippets
#define LSTART ('a')
#define USTART ('A')
#define NALPHA ('z' - 'a' + 1)int ascii_offset = islower (ec) ? LSTART : USTART;
wrap = (ec + offset - ascii_offset) % NALPHA;
wrap = (wrap < 0) ? NALPHA + wrap : wrap;
ec = islower(ec) ? wrap + LSTART : wrap + USTART;const int ascii_offset = islower(ec) ? LSTART : USTART;
int wrap = (ec + offset - ascii_offset) % NALPHA;
if (wrap < 0) {
wrap += NALPHA;
}
ec = wrap + ascii_offset;Context
StackExchange Code Review Q#37336, answer score: 6
Revisions (0)
No revisions yet.