Caesar Cipher shifting characters - c

I had received this assignment last month and ended up getting it wrong because of the problem I will state after this. Currently, I am doing Caesar's Cipher and I believe I have the right format. I ask the user for a string and I encrypted with a key == 3. However, I want to loop around the alphabet if the plaintext letter is X, Y, Z, x, y, or z. But, when I put those any of those characters in, I do not get A, B, and C, but ]... and other braces. Any hints to fix the problem.
Thank you!
void main()
{
int key = 3;
char string[256];
int i = 0;
printf("Enter the string you want encrypted\n");
fgets(string, sizeof(string), stdin);
for (i = 0; i < strlen(string); i++) {
if (string[i] == ' ') {;}
else if ((string[i] >= 'a' && string[i] <= 'z' || string[i] >= 'A' && string[i] <= 'Z')){
string[i] = string[i] + key;
}
}
printf("Cipher text:%s",string);
}

You need to look at the ASCII table: http://www.asciitable.com/. You're using an ASCII encoding of the characters.
Z has a decimal value of 90, so 93 is ']'. You need to manually wrap back around to the beginning of the alphabet. This is best done with a modulo and adding the ASCII value of the first alphabetic character. It's up to you how you wrap capital letters (back to 'a' or to 'A').

You need to convert the character to its position in the alphabet, then find the result modulo 26 (alphabet length), then convert it back to the character. Something like:
char base = 0;
if(string[i] >= 'a' && string[i] <= 'z'){
base = 'a';
}else if(string[i] >= 'A' && string[i] <= 'Z'){
base = 'A';
}
if(base){
string[i] = ((string[i] - base) + key) % 26 + base;
}

You almost got it:
#include <stdio.h>
#include <string.h>
int main() {
char string[256];
int i = 0;
int key = 3;
const int num_letters = 26;
printf("Enter the string you want encrypted\n");
fgets(string, sizeof(string), stdin);
for (i = 0; i < strlen(string); i++) {
if (string[i] >= 'a' && string[i] <= 'z') {
string[i] = 'a' + (string[i] - 'a' + key) % num_letters;
}
else if (string[i] >= 'A' && string[i] <= 'Z') {
string[i] = 'A' + (string[i] - 'A' + key) % num_letters;
}
}
printf("Encrypted: %s\n", string);
return 0;
}
Enter the string you want encrypted
Zorro
Encrypted: Cruur
In C you can use the modulo operator % to wrap around, as shown above. Good luck!

Related

C language - return a value from function as function parameter

I have a problem with my homework. I need to count quantity of upper case and quantity of vowels in string. Unfortunately, it always returns number 0 which looks as it doesn't change in function. Everything works until this one.
Here is my code:
#include <stdio.h>
#include <conio.h>
#include <string.h>
char *StringChange(char *text, int *upper, int *chars);
int main(void) {
char text[40];
int upper, chars;
puts("Type a string");
gets(text);
StringChange(text, &upper, &chars);
puts("Change words to start with upper case and change white spece to *");
puts(text);
printf("Quantity of upper case in string: %d\n", upper);
printf("Quantity of vowels: %d", chars);
getch();
return 0;
}
char *StringChange(char *text, int *upper, int *chars) {
int i, length;
length = strlen(text);
for (i = 1; i <= length; i++) {
if (text[i - 1] == '*' && (text[i] >= 'a' && text[i] <= 'z')) {
text[i] = text[i] - 32;
}
if (text[i] == ' ') {
text[i] = '*';
}
if (text[i] >= 'A' && text[i] <= 'Z') {
*upper = *upper + 1;
/* *upper++; that also doesn't work */
}
if (text[i] == 'a' || text[i] == 'e' || text[i] == 'i' || text[i] == 'o' || text[i] == 'u' || text[i] == 'y') {
*chars = *chars + 1;
/* *chars++; that also doesn't work */
}
}
if (text[0] >= 'a' && text[0] <= 'z') {
text[0] = text[0] - 32;
}
return (text);
}
I tried your code and I do get non-zero results -- depending on the input, of course, so maybe you are only testing on strings that produce zero.
However, the results are not always correct. There are two problems I found in the code:
1) As pointed out in a comment, you should initialize upper and chars to 0.
2) You are starting the loop at index 1, not index 0. I think you did this so you could look at text[i-1] inside the loop, but it is causing you to exclude the first character from your totals. You should start the loop index and 0 and figure out a different way to handle it within the loop. (Hint - note that the first if within the loop and the one following the loop have similar conditions and the same body.)
There are multiple issues in your code:
you should never use gets().
the variables upper and chars are not initialized
the function StringChange make a special case of text[0] but does not update the counts for this initial byte.
you hard code the conversion of lowercase to uppercase for ASCII.
you should stop at the end of the string
all white space is not replaced, on whitespace followed by a lowercase letter.
uppercase vowels should be counted too.
Here is a modified version:
#include <stdio.h>
char *StringChange(char *text, int *upper, int *chars);
int main(void) {
char text[200];
int upper, vowels;
puts("Type a string");
if (fgets(text, sizeof text, stdin)) {
StringChange(text, &upper, &chars);
puts("Change words to start with upper case and change white space to *");
puts(text);
printf("Quantity of upper case in string: %d\n", upper);
printf("Quantity of vowels: %d\n", vowels);
}
getchar();
return 0;
}
char *StringChange(char *text, int *upper, int *vowels) {
int i, at_start = 1;
*upper = *vowels = 0;
for (i = 0; text[i] != '\0'; i++) {
char c = text[i];
if (at_start && c >= 'a' && c <= 'z') {
c += 'A' - 'a';
text[i] = c;
}
if (c == ' ') {
c = '*';
text[i] = c;
at_start = 1;
} else {
at_start = 0;
}
if (c >= 'A' && c <= 'Z') {
(*upper)++; // *upper++ would just increment the pointer, leading to undefined behavior
}
if (strchr("aeiouyAEIOUY", c) {
(*vowels)++;
}
}
return text;
}

How do I fix the looping from 'z' back to 'a' in my Vigenere Cipher

My Vigenere cipher has problems. When I input my message, the result comes out fine, but if the letter goes past 'z', it doesn't loop back to 'a', and is printing out other ascii characters. Moreover, when I put the message in, I sometimes get more characters than I needed. ex: key is hello, message is mmmmm(I know, not much of a message, but it's an example), and the output is tqxx{{. PLEASE HELP!!!!
#include<cs50.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
int main( int argc, char *argv[])
{
char *k;
if (argc!=2)
{
printf("Give one argument, not 2, not 3, not 4 , and not any other amount other than one");
printf("\n");
return 1;
}
k = argv[1];
printf("What is the message? ");
string message = get_string();
if (strlen(k)<strlen(message))
{
printf("Invalid response\n");
return 0;
}
for (int i = 0, l = 0; i < strlen(message); i++, l++)
{
int x;
if (message[i]>='A' && message[i] <='Z')
{
message[i] = message[i]-'A';
message[i] = message[i] + (k[l] - 'A') % 26;
message[i] = message[i] + 'A';
message[i] = (char) x;
if (x > 90)
{
x = x - 26;
message[i] = (char) x;
}
printf("%c", message[i]);
}
if(message[i] >='a' && message[i] <= 'z')
{
message[i]= message[i]-'a';
message[i] = message[i] + (k[l] - 'a') % 26;
message[i] = message[i] + 'a';
printf("%c", message[i]);
}
if ((message[i] < 'A') || (message[i] > 'z') || (message[i] > 'Z' && message[i] < 'a'))
{
printf("%c", message[i]);
}
}
printf("\n");
return 0;
}
You should put brackets around the message[i] + (k[l] - 'a') part. The modulo goes only for the second part - (k[l] - 'a') - while you want it to apply to the whole expression.
Also, you assume k[l] is the same case as message[i] (upper/lowercase), but that's not necessarily true. You should have another condition in each of the inner branches, or (preferable), calculate the numeric values of k's letters and store them as numbers in range 0-25.
Third, why is x there? It's used when uninitialized, and generally I don't see a reason for it's existence.
Last thing, you should probably set l to zero again when it reaches the end of k, in case the message is longer than the key.

Why does my palindrome checking function always return false for palindromes?

I'm trying to check if a sentence is palindrome or not. Neither space nor punctuation matter.
Examples:
• Never odd or even
• A man a plan a canal Panama.
• Gateman sees name, garageman sees name tag
Netheir of this sentences passes true on my code.
On my first for I try to remove spaces, punctuation and transform upper letters in lower.
int palindrome(char *str){
int n,n2 = 0,i,j=0;
n = sizeof(str)/sizeof(char);
char nova[n];
for (i=0;i< n;i++){
if(str[i] >= 'A' && str[i] <= 'Z'){
nova[n2] = ('a' + str[i] - 'A');
n2++;
}
else if(str[i] >= 'a' && str[i] <= 'z'){
nova[n2] = str[i];
n2++;
}
}
i=0;
while (i < n2-1){
if (nova[i]!= nova[j]){
return 0;
}
i++;
j--;
}
return 1;
}
line 4: you want to get the count of elements by sizeof.
But if you transfer your arguments to function by pointer.
n = sizeof(str)/sizeof(char);
n will always be 4 (on 32 bit platforms). Instead, use
n = strlen(str)
(need to #include <string.h>) if it is a string format in c.
The existing answer is good, but there is another way to solve this problem, without using additional allocated memory. You don't really need to store the letters anywhere in order to compare them - you can use pointers to your original string.
int palindrome(char *str)
{
int i = 0, j = strlen(str);
while (i < j)
{
if (str[j] == '\0' || !isalpha(str[j]))
--j; // skip the character on the right if it's not a letter
else if (!isalpha(str[i]))
++i; // skip the character on the left if it's not a letter
else if (tolower(str[i]) != tolower(str[j]))
return 0; // letters are different? - not a palindrome
}
// all letters were equal? - a palindrome
return 1;
}
Ok, now with all the modifications it works. Thanks guys.
int palindrome(char *str)
{
int n =0,i=0,j;
char nova[100];
while(str[i]!= '\0'){
if(str[i] >= 'A' && str[i] <= 'Z'){
nova[n] = ('a' + str[i] - 'A');
n++;
}
else if(str[i] >= 'a' && str[i] <= 'z'){
nova[n] = str[i];
n++;
}
i++;
}
i=0;
j= n-1;
while (i< j){
if (nova[i]!= nova[j]){
return 0;
}
i++;
j--;
}
return 1;
}

Caesar's Cipher in C: can't seem to wrap around the latter letters of the alphabet

#include <stdio.h>
int main()
{
char text[1000], alpha;
int n;
printf("Please type in text:\n");
scanf("%[^\n]s", text);
printf("\nRotation number: "); // rotates letters to the right.
scanf("%d",&n);
printf("\n");
n = n % 26; // to wrap around alphabet.
int i = 0;
while (text[i] != '\0')
{
if((text[i] >= 'a' && text[i] <= 'z'))
{
alpha = text[i];
text[i] += n;
This is the part which I do not understand why it isn't working:
if(text[i] > 'z')
{
text[i] = 'a' + (n - (26 % (alpha - 'a')));
}
It works until the letter 'd'. 'f' just gives '\200'.
Any ideas as to why my code does not work?
}
i++;
}
printf("Encrypted text:\n%s", text);
return 0;
}
This part which you do not understand why is not working:
if(text[i] > 'z')
{
text[i] = 'a' + (n - (26 % (alpha - 'a')));
}
would be simply solved with
if(text[i] > 'z')
{
text[i] -= 26;
}
UPDATE you are working with char whick is probably signed, so adding the cipher, say, 20 to z will produce a number that is > 128, ie negative.
I suggest this amendment
int alpha; // changed from char
//...
alpha = text[i] + n;
if (alpha > 'z')
alpha -= 26;
text[i] = alpha;
I think what you want is
text[i] = (text[i] - 'a' + n) % 26 + 'a';
which does this
text[i] - 'a' // converts text[i] to a number between 0 and 25
+ n // add the cipher value
% 26 // wrap as necessary so the value is between 0 and 25
+ 'a' // convert back to a letter between 'a' and 'z'
So the loop should look like this
for ( int i = 0; text[i] != '\0'; i++ )
{
if ( text[i] >= 'a' && text[i] <= 'z' )
text[i] = (text[i] - 'a' + n) % 26 + 'a';
}

How to Copy the (ASCII) alphabetic characters contained in an existing string into a new one

The new string should contain only the alphabetic characters from the existing string in the same order. Non-alphabetic characters should be not be copied. If s is a null pointer, return a null pointer.
Example input:
"Ready... aim... fire!"
Output:
Readyaimfire
I don't know why in my first for loop, the code never enters the if statement. I'm also not sure if I allocated the memory for the new string correctly. Thanks for any help :)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *alphabetic (const char *s);
char *alphabetic (const char *s)
{
char *newChar;
int i;
char n = 0;
long length = strlen(s);
for(i=0; i<length; i++)
{
if( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
{
n++;
}
}
newChar = (char*)malloc(sizeof(char)*n);
for(i=0; i<length; i++)
{
if( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
{
newChar[i] = s[i];
}
}
return newChar;
}
int main (void)
{
char *a, *b, *c;
a = alphabetic ("Ready... aim... fire!");
b = alphabetic ("***");
c = alphabetic ("*a*b*c*");
printf ("%s\n", a);
printf ("%s\n", b);
printf ("%s\n", c);
free(a);
free(b);
free(c);
return 0;
}
The conditional of the first if and the conditional of the second if are such that if one is true then the other is false. Hence, you never get to the line
n++;
You need
if ( (s[i] <= 122 && s[i] >= 97) || (s[i] <= 90 && s[i] >= 65) )
To make the code more readable, you can make it:
if ( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
If you have the option of using the standard library, you can just use:
if ( isalpha(s[i]) )
BTW, the line
s = s + i;
is going to mess things up. As you iterate through the loop, you'll end up skipping parts of the input string. Remove that line.
You Can use a single loop of that
int j = 0; //take integer variable
for(i=0; i<length; i++)
{
if( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
{
//n++; //Remove this
newChar[j] = s[i];
j++;
}
}
Things about your code:
n should be n+1 to accommodate '\0' character
2nd for loop: you need to have another variable say j =0 and incremented on every match. You can't use i for the newChar array as in the original array s,since i might point to an address that's outof bounds in the newChar array.For ex: ready...aim, newchar # elements 8 while s =11
So saying newChar[8]=s[8] is wrong,rather it should be newChar[5]=s[8].
Posting the corrected code:
char *alphabetic (const char *s)
{
char *newChar;
int i,j=0; //Change1: extra variable j to keep a track of elements for newChar
char n = 0;
long length = strlen(s);
for(i=0; i<length; i++)
{
if( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
{
n++;
}
}
newChar = (char*)malloc(sizeof(char)*(n+1)); // Change2: n+1 instead of n
for(i=0; i<length; i++)
{
if( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
{
newChar[j++] = s[i]; //Change3: j instead of i
}
}
newChar[j]='\0'; //Termination of strings
return newChar;
}
I can't tell you why your code doesn't enter the if statement because you didn't provide the test case (input data) on which the algorithm does not enter the if statement. What I can tell you is that it won't do what you want it to do. Let's break down the for loop for a moment here:
it says "make variable i = 0, then, while i is smaller then the length of char array s, do some stuff then increment i". This is a very handy way to parse a char array. That's just fine and dandy, but inside the for loop, the first instruction is s = s + i. What that will do is move the pointer s forward by i characters at each iteration. Keep in mind that i will increase with time. Say we give that function the char * "This is a sentence.". The function strlen(s) will return 19 (which will be stored in length) and thus the for loop will iterate 19 times, with i taking values from 0 to 18 including. Let's see what's happening to s in there. First time, *s value is T. When you make s = s + i (i = 0), *s will still be T. T's ascii code is 84 and the if checks for values between 97 and 122 (including). So that's that for the first iteration. Then i becomes 1. And s moves one position further, thus *s will be 'h'. The ASCII code for the letter h is 104, so it enters the first if (because it is beween 122 and 97). Then, you ask if s[i] is beween 90 and 65. Now, because you incremented s, *s is 'h', but i == 1 at this point and thus s[i] is actually 'i' (whose ASCII code is 105 and thus never entering that loop). So if you wanna increment your n with your given algorithm I would say you need an input test case looking like so: "ThIsiSaSENtENCE". What you want is a clean string parsing for loop with another clean if to check whether the current character is a letter:
for(i = 0; i < length; i++)
{
if((s[i]<='Z' && s[i] >= 'A') || (s[i]<='z' && s[i]>='a'))
n++;
}
This will count how many letters are there in your char array s.
EDIT:
If you wanna remove those characters which are not letters and return the new string then you might wanna try something like this (NOT OPTIMAL):
char *copyStringByLetter(char *arg, int size)
{
int i = 0;
int n = 0;
for(i = 0; i < size; ++i){
if((s[i]<='z' && s[i]>='a')||(s[i]<='Z' && s[i]>='A'))
n++;
}
char *result = malloc(n+1); //need #include <stdlib.h>
if(!result){
fprintf(stderr, "Error alocating memory!");
exit(EXIT_FAILURE) //you need #include <stdlib.h> for this
}
int j = 0;
for(i = 0; i < size; i++){
if((s[i]<='z' && s[i]>='a')||(s[i]<='Z' && s[i]>='A')){
result[j] = s[i];
j++;
}
}
result[j] = '\0' //terminate the array
return result;
}
If you want to ask me why I am sending the length of char array as an argument, it is to prevent char overruns (who happen more often than you might think)

Resources