Ampersand
Ampersand

Reputation: 446

Building a Caesar Cipher Decoder in C

I'm new to C and this was a bonus question for an assignment that came and went but I'm still trying to puzzle through it.

The aim is to accept input from a file that is encoded with the Caesar Cipher (move letters left or right in alphabet), figure out which letter has the highest frequency then use this to guess the shifting value and decode the input.

I separately managed to read the frequency and calculate the shifting value, and then decode the input using the result from this. But I can't make it work when I put everything back together in one file. In fact it doesn't even look like it is doing anything right now besides going through main and printing Success1.

Any suggestions on how to improve this or reasons why it isn't working would be great. I feel like I'm about 90% there but can't figure out that last 10%.

Thanks.

int count_freq( int count[] );
int decode( int shift, int ch );
int rotate_right( int ch );
int rotate_left( int ch );

                                                                               // count the number of occurrences of each letter
int count_freq( int count[] )
{
  int ch;
  int shift, maximum, size = 26, c, location = 1, i;

  while(( ch = getchar()) != EOF ) 
    {
        ch = toupper( ch );                                                     // convert to upper case
        if( ch >= 'A' && ch <= 'Z' ) 
        {
            i = ch - 'A';
            count[i]++;                                                         // increment i'th element
        }
    } 

    maximum = count[26];                                                        //Sets maximum size of count

    for( c = 1; c < size; c++ )
    {
        if( count[c] > maximum )                                                //not 100% sure what is happening here but it works
        {
          maximum = count[c];
          location = c+1;
        }
    }

    shift = 5-(location-1);                                                     //Compares the value of the letter with the highest frequency to E to find the shift
    return(shift);
    printf("shift = %d", shift );
    printf("Success2"); 
}

int decode( int ch, int shift)
{
    int j;
     if( shift >= 0 ) 
    {                                                                           //If shift is greater than zero
           for( j=0; j < shift; j++ )                                           //Start at i=0, increment by one while i is less than shift
           {              
                     ch = rotate_right( ch );                                   //Use the function that increases the characters
           }
    }
    else 
    {                                                                           //For shifting values less than zero      
           for( j=0; j < -shift; j++ )                                          //Start at i=0, increment by one while i is less than negative shift (ie. if shifting value is -10 this goes up to i=10)
           {                 
                     ch = rotate_left( ch );                                    //Use the function that decreases the characters        
           }
    }

    printf("Success3");     
}

int rotate_right( int ch )
{
   if( ch == 'Z' ) {                                                            //If the character is Z then make it A
      return( 'A' );
   }
   else if( ch == 'z' ) {                                                       //Same for lower case
      return( 'a' );
   }
   else if(  ( ch >= 'A' && ch < 'Z' )                                          //If the Character is greater than or equal to A and less than Z, add one to the value of the character. Eg. B -> C
           ||( ch >= 'a' && ch < 'z' )) {
      return( ch + 1 );
   }
   else {                                                                       //This is for the characters that are not letters. Punctuation and spaces
      return( ch );
   }
   printf("Success4");
}

int rotate_left( int ch )                                                       //This is all the same but it shifts the value of the characters the other way. Eg. C -> B                   
{
   if( ch == 'A' ) {
      return( 'Z' );
   }
   else if( ch == 'a' ) {
      return( 'z' );
   }
   else if(  ( ch > 'A' && ch <= 'Z' )
           ||( ch > 'a' && ch <= 'z' )) {
      return( ch - 1 );
   }
   else {
      return( ch );
   }
   printf("Success5");
}

int main( )
{
    int count[26] = { 0 };                                                      //Initialize array elements
    int ch, shift;
    count_freq( count );                                                        //Count frequencies

    while(( ch = getchar()) != EOF )                                            //While the variable ch is not the end of the string entered
    {     
         putchar( decode( ch, shift ));                                         //Calls the decode function from above using ch from getchar and shift from scanf 
    }

    printf("Success1");
    return 0;
}

Upvotes: 1

Views: 655

Answers (3)

Barmak Shemirani
Barmak Shemirani

Reputation: 31679

You need to use modulus operator % to shift characters

result = 'A' + (c - 'A' + shift) % 26

% 26 ensures no character goes out of range.

If shift is 2 and character is 'A' => result is 'C'

If shift is 2 and character is 'Z' => result is 'B'

To decode the message, change shift to 26 - shift.

void rotate(char* msg, int shift)
{
    for (int i = 0, len = strlen(msg); i < len; i++)
    {
        if (msg[i] >= 'a' && msg[i] <= 'z')
            msg[i] = 'a' + (msg[i] - 'a' + shift) % 26;
        else if (msg[i] >= 'A' && msg[i] <= 'Z')
            msg[i] = 'A' + (msg[i] - 'A' + shift) % 26;
    }

    printf("%s\n", msg);
}

void encode(char* msg, int shift)
{
    rotate(msg, shift);
}

void decode(char* msg, int shift)
{
    rotate(msg, 26 - shift);
}

int main()
{
    char message[100];
    strcpy(message, "ABCD XYZ");
    encode(message, 2);
    decode(message, 2);
    return 0;
}

Upvotes: 1

powerc9000
powerc9000

Reputation: 2103

First thing I notice:

You never use intialize shift when you call count_freq()

So when you pass shift to decode it gets passed as a garbage value of whatever is on the stack.

Upvotes: 2

Bill Lynch
Bill Lynch

Reputation: 82026

At the very minimum, your code doesn't work because there are no return statements in decode().

If your compiler didn't warn / error on this, you should get a better compiler.

Upvotes: 2

Related Questions