Caesar Cipher Negative Numbers Issue - c

I'm trying to write a caesar cipher program that takes an argument, converts it into an integer, and uses that as to shift the letters in a certain direction (positive numbers shift it forward and negative numbers shift it backwards. So far all the program works for all positive numbers but does not for negative numbers.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int encrypt(int character, int shift);
int main(int argc, char * argv[]) {
int shift = atoi(argv[1]);
if (shift >= 26) {
shift = ((shift + 26) % 26);
}
int character = getchar();
while (character != EOF) {
int new_character = encrypt(character, shift);
putchar(new_character);
character = getchar();
}
return 0;
}
int encrypt(int character, int shift) {
int ch = character;
int negShift = shift;
if (ch >= 'a' && ch <= 'z') {
ch = ch + shift;
if (ch > 'z') {
ch = ch - 'z' + 'a' - 1;
}
} else if (ch >= 'A' && ch <= 'Z') {
ch = ch + shift;
if (ch > 'Z') {
ch = ch - 'Z' + 'A' - 1;
}
}
return ch;
}

You could just add the 26 to ch when ch < 'a' or ch <'A'.
Consider below example.
if(ch < 'a')
{
ch = ch + 26;
}
Full code.
int encrypt(int character, int shift) {
int ch = character;
int negShift = shift;
if (ch >= 'a' && ch <= 'z') {
ch = ch + shift;
if (ch > 'z') {
ch = ch - 'z' + 'a' - 1;
}
else if(ch < 'a')
{
ch = ch + 26; //Here
}
} else if (ch >= 'A' && ch <= 'Z') {
ch = ch + shift;
if (ch > 'Z') {
ch = ch - 'Z' + 'A' - 1;
}
else if(ch < 'A')
{
ch = ch + 26; // Here
}
}
return ch;
}

Related

why the program omitted some lines? (c program to encrypt text)

i am trying to make a program that encrypt text with a Caesar cipher.The number of positions to shift will be given to the program as a command line argument and characters other than letters should not be encrypted. The program should stop only at the end of input. My issue is that the program omit the lines that mod the number. the program is run on a platform that provided by my school, i am not sure what it is. please kindly help me to fix the program.
here is my program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( int argc, char *argv[] ) {
int num = atoi(argv[1]);
char caesar[100];
char ch;
int shift = num%26;
while ( fgets(caesar, 100, stdin) != NULL){
for(int i = 0; i < strlen(caesar); i++){
ch = caesar[i];
if( ch >= 97 && ch <= 122){
if( ch + shift < 97){
ch = ch + shift + 26;
}
else if( ch + shift > 122){
ch = ch + shift - 26;
}
else{
ch = ch + shift;
}
caesar[i] = ch;
}
else if( ch >= 65 && ch <= 90){
if( ch + shift < 65){
ch = ch + shift + 26;
}
else if( ch + shift > 90){
ch = ch + shift - 26;
}
else{
ch = ch +shift;
}
caesar[i] = ch;
}
}
}
printf("%s", caesar);
return 0;
}
here is some examples which have correct output
here is what my program did. the program ignored shift = num%26 and i can't figure out why

Test if the input is integer or symbol in fgets in C

I am constructing a program that takes string input from the keyboard then shows the number of consonants as an output. I have managed to do it in a ridiculous way in the function count_consonants. I tested using if statement whether each character in the input is a number or symbol to ignore them during calculations. I originally wanted to check if the string is not a string using fgets but I don't know how. That's not an effective way, so any ideas for this?
#include <stdio.h>
#include <string.h>
//function to calculate the consonants
int count_consonants(char str[]) {
int idx;
for (idx = 0; idx < 100; ++idx) {
if (str[idx] == '\0') {
break;
}
}
int vowl = 0;
for (int i = 0; i < idx; ++i) { //loop to check if the characters are vowels or not
if (str[i] == 'a' || str[i] == 'e' || str[i] == 'i' || str[i] == 'o'
|| str[i] == 'u' || str[i] == 'A' || str[i] == 'E' || str[i] == 'I'
|| str[i] == 'O' || str[i] == 'U' || str[i] == ' ') {
vowl += 1;
}
// numbers and symbols are counted here as vowels because if not,
// the compiler will count them the other way around
if (str[i] == '1' || str[i] == '2' || str[i] == '3' || str[i] == '4'
|| str[i] == '5' || str[i] == '6' || str[i] == '7' || str[i] == '8'
|| str[i] == '9') {
vowl += 1;
}
if (str[i] == ':' || str[i] == ',' || str[i] == '.' || str[i] == '$'
|| str[i] == '%' || str[i] == '^' || str[i] == '&' || str[i] == '*'
|| str[i] == '#' || str[i] == '_' || str[i] == '!') {
vowl += 1;
}
}
int cons = idx - vowl; // consonants = whole length of text - vowels
return cons - 1;
}
int main(int argc, char const *argv[]) {
char string[100];
char store[100][100];
int i = 0;
while (string[0] != '\n') {
fgets(string, 100, stdin);
strcpy(store[i], string);
i++;
}
for (int j = 0; j < i - 1; ++j) {
/* code */
printf("Number of consonants=%d\n", count_consonants(store[j]));
}
return 0;
}
shows the number of consonants
A simply way to count consonants, use isalpha(), strchr()
#include <string.h>
#include <ctype.h>
int my_isavowel(char ch) {
const char *p = strchr("aeiouAEIOU", ch); // search for a match
return p && *p; // If p is not NULL, and does not point to \0
}
int count_consonants(const char str[]) {
int count = 0;
while (*str != '\0') { // while not at end of string ...
char ch = *str++; // Get character and advance
count += isalpha((unsigned char) ch) && !my_isvowel(ch);
}
return count;
}
If you look for number of consonants, simply best count consonants instead of other things
#include <stdio.h>
#include <string.h>
int main (int narg,char*args[]){
char cons[ ] = "ZRTPQSDFGHJKLMWXCVBN";
char sentence[ ] = "This is my sentence!";
int i=0;
int sum_cons = 0;
for (i = 0; i < strlen(sentence); ++i)
if (strchr(cons,strupr(sentence)[i])) sum_cons++;
printf ("#CONS>%i\n",sum_cons);
return 0;
}

Conversion of hexadecimal string constant to decimal value using C

The following program gives the result as 0 instead of the expected decimal equivalent of the hexadecimal string constant.
#include <stdio.h>
int my_htoi(char[]);
int main(void) {
printf("%d", my_htoi("0xABC"));
return 0;
}
int my_htoi(char str[]) {
int i, num = 0;
for (i = 0; i != '\0'; ++i) {
if (str[i+1] == 'x' || str[i+1] == 'X') {
i = i + 1;
continue;
}
if (str[i] >= '0' && str[i] <= '9') {
num = num * 16 + (str[i] - '0');
} else if (str[i] >= 'a' && str[i] <= 'f') {
num = num * 16 + (str[i] - 'a' + 10);
} else if (str[i] >= 'A' && str[i] <= 'F') {
num = num * 16 + (str[i] - 'A' + 10);
}
}
return num;
}
While the following program runs fine and outputs the correct decimal equivalent of the hexadecimal string constant.
#include <stdio.h>
#include <string.h>
int my_htoi(char[]);
int main(void) {
printf("%d", my_htoi("0xABC"));
return 0;
}
int my_htoi(char str[]) {
int i, num = 0;
for (i = 0; i < strlen(str); ++i) {
if (str[i+1] == 'x' || str[i+1] == 'X') {
i = i + 1;
continue;
}
if (str[i] >= '0' && str[i] <= '9') {
num = num * 16 + (str[i] - '0');
} else if (str[i] >= 'a' && str[i] <= 'f') {
num = num * 16 + (str[i] - 'a' + 10);
} else if (str[i] >= 'A' && str[i] <= 'F') {
num = num * 16 + (str[i] - 'A' + 10);
}
}
return num;
}
The only difference is in the way we find the qualifying condition for the loop. Why does it not work with the null byte checking?
Wrong code: i != '\0' checks if the index is 0.
for(i = 0; i != '\0'; ++i) {
Should be the below to check if the element str[i] is the null character.
for(i = 0; str[i] != '\0'; ++i) {
Other issues exists unneeded increment, int overflow (better to use unsigned here), wrong x detection - consider "0x0x0x1", leading - or +, char str[] --> const char str[], ...
There are some problems in your code:
the loop index i is compared to '\0' instead of str[i], causing immediate termination of the loop with a return value of 0.
the test for x is incorrect: it would cause "1x2" to convert to 2 instead of 1.
you accept letters beyond f and convert them to digits. The function should instead stop parsing at the first character that is not a hex digit.
Here is a corrected version:
#include <stdio.h>
int my_htoi(const char[]);
int main(void) {
printf("%d", my_htoi("0xABC"));
return 0;
}
int my_htoi(const char str[]) {
int i = 0, num = 0;
if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
i += 2;
for (; str[i] != '\0'; ++i) {
if (str[i] >= '0' && str[i] <= '9') {
num = num * 16 + (str[i] - '0');
} else if (str[i] >= 'a' && str[i] <= 'f') {
num = num * 16 + (str[i] - 'a' + 10);
} else if (str[i] >= 'A' && str[i] <= 'F') {
num = num * 16 + (str[i] - 'A' + 10);
} else {
break;
}
}
return num;
}

Circular shift cipher

I have written a circular shift cipher for key -1 billion to +1 billion for encrypting messages of maximum 200 characters including 0 to 9, a to z and A to Z.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char input[215], key[11], msg[201], output[201], ch;
int i, j, k, shiftkeychar, shiftkeynum;
printf("Input: ");
gets(input);
for (i = 0; input[i] != ':'; i++)
key[i] = input[i];
key[i] = '\0';
i++;
k = 0;
for (j = i; input[j] != '\0'; j++) {
msg[k] = input[j];
k++;
}
msg[k] = '\0';
printf("\nmessage: %s\n", msg);
printf("key: %s\n", key);
shiftkeychar = atoi(key) % 26;
shiftkeynum = atoi(key) % 10;
printf("shiftkey for characters: %d\n", shiftkeychar);
printf("shiftkey for numbers: %d\n", shiftkeynum);
strcpy(output, msg);
for (i = 0; output[i] != '\0'; i++) {
ch = output[i];
if (ch >= 'A' && ch <= 'Z') {
ch = ch + shiftkeychar;
if (ch > 'Z') {
ch = ch - 'Z' + 'A' - 1;
}
else if (ch < 'A') {
ch = ch + 'Z' - 'A' + 1;
}
}
else if (ch >= 'a' && ch <= 'z') {
ch = ch + shiftkeychar;
if (ch > 'z') {
ch = ch - 'z' + 'a' - 1;
}
else if (ch < 'a') {
ch = ch + 'z' - 'a' + 1;
}
}
else if (ch >= '0' && ch <= '9') {
ch = ch + shiftkeynum;
if (ch > '9') {
ch = ch - '9' + '0' - 1;
}
else if (ch < '0') {
ch = ch + '9' - '0' + 1;
}
}
output[i] = ch;
//printf("output[%d]: %c", i, ch);
}
printf("Output: %s", output);
return 0;
}
This Circular shift cipher is working well for Capital letters and digits. However for small letters e.g. if message is 'xyz' and key is more than 5 (i.e., 6,7,...25) its generating some arbitrary output. input format is: "key:message". output is:"encrypted message".
Your character ch is a char, which in C may or may not be signed. On your machine, it seems to be signed, which means that you can store values from −128 to 127. The lower-case letters occupy the ASCII codes from 97 to 122. When you say:
ch = ch + shiftkeychar;
you may overflow the signed char for letters at the back of the alphabet. Technically, this is undefined behaviour; in practice you will probably get negative values, which will lead to strange characters later on.
To resolve your problem, make ch an int.

How to repeat characters in array

I am trying to implement Vigenere's Cipher in C but the problem is that when I try to repeat the key used in the array it is in, it breaks after the 4th letter. So if the key is ABC and the plaintext is HELLO, it returns HFNLO instead of HFNLP. When I look at my code it logically makes sense but it seems to just not work. Can anybody see the problem?
Here is the code:
int main(int argc, string argv[])
{
if(argc != 2)
{
printf("usage: ./vigenere k\n");
return 1;
}
//asks for plain text
printf("plaintext: ");
string text = get_string();
string k = argv[1];
printf("ciphertext: ");
//checks to see if length of key is shorter than length of plaintext and duplicates it.
int count = 0;
while(strlen(k) <= strlen(text))
{
k[strlen(k + count)] = k[count];
count++;
}
//changes key to be within 0 - 25 and encrypts plaintext
for(int i = 0; i < strlen(text); i++)
{
if(k[i] >= 'A' && k[i] <= 'Z')
{
k[i] = k[i] - 65;
}
else if (k[i] >= 'a' && k[i] <= 'z')
{
k[i] = k[i] - 97;
}
//if statement for plaintext capital letters
if(text[i] >= 'A' && text[i] <= 'Z')
{
text[i] = text[i] - 64;
text[i] = ((text[i] + k[i]) % 26) + 64;
}
//if statement for plaintext lowercase letters
else if(text[i] >= 'a' && text[i] <= 'z')
{
text[i] = text[i] - 96;
text[i] = ((text[i] + k[i]) % 26) + 96;
}
//prints final cipher
printf("%c", text[i]);
}
printf("\n");
return 0;
}
You should use the modulo operator to compute the offset into the key.
Here is a modified version:
#include <stdio.h>
#include <string.h>
#include <cs50.h>
int main(int argc, string argv[]) {
if (argc != 2) {
printf("usage: ./vigenere k\n");
return 1;
}
string k = argv[1];
size_t klen = strlen(k);
if (klen == 0) {
fprintf(stderr, "vigenere: key must not be empty\n");
return 1;
}
printf("plaintext: ");
string text = get_string();
printf("ciphertext: ");
for (size_t i = 0; text[i] != '\0'; i++) {
int d = (unsigned char)k[i % klen];
if (d >= 'A' && d <= 'Z') {
d -= 'A';
} else
if (d >= 'a' && d <= 'z') {
d -= 'a';
} else {
d = 0;
}
int c = (unsigned char)text[i];
if (c >= 'A' && c <= 'Z') {
c = 'A' + (c - 'A' + d) % 26;
} else
if (c >= 'a' && c <= 'z') {
c = 'a' + (c - 'a' + d) % 26;
}
putchar(c);
}
putchar('\n');
return 0;
}

Resources