1

Okay, the code is given below (forgive me if there are too many comments!!). Please help!!

Code:


//the objective of the program is to create a simple encryption of the text inputted by the user with a key also given by the user as a command-line argument
// how the encryption works is that each character is shifted by k places, where k is the key. for example, if the key is 2, a becomes c; b becomes d and likewise, z becomes b
// note, we need to preserve case in the encoded text and all characters other than alphabets should be left as it is, so numbers, special characters, spaces, etc are not affected

#include <stdio.h>
#include <stdlib.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>

int k; // Global variable

char digit(char a);
char digitchecker(string a);


int main(int argc, string argv[]) // We need a command line argument, and argc counts the number of words in input and string argv stores them
{       if (argc != 2) // we need two command line arguments so anything else should prompt the user to enter in the correct format,ie, ./caesar key, where key is the second command line argument
   {
       printf("Usage: ./caesar key\n");
       return 1; // Terminates the program prematurely.
   }
   if (argc == 2) //when the user inputs correctly
   {
       if (digitchecker(argv[1]) == 'n') // the second commandline argument that is the key, should be purely numeric. this checks for that. returns a boolean value, true / false or 1 / 0
       {
           printf("Usage: ./caesar key\n");// if it is false, the program is terminated with the message again
           return 1; // same as before
       }
       if (digitchecker(argv[1]) == 'y') // the condition if key is numeric, which is what we want
       {
           char *r = argv[1]; // conversion of command line argument for storage using pointers
           k = atoi(r); //stores the key
           string plaintext = get_string("Plaintext: "); // Gets the plaintext from user as a string
           int strlength = strlen(plaintext); // stores the length of the string as an integer
           char ciphertext[strlength]; // declaring the cipher text
           for (int i = 0; i < strlength; i++) // for loop for encoding with key
           {
               int a = (int) plaintext[i]; // stores the value of the i th index of plaintext, such that plaintext itself does not get modified as it is an array
               if (isalpha(a) == 0) // we do not want to encrypt space or special characters like .,;@ etc or numbers, so we us isalpha to stay clear of them, as isupper returns 0 if false
                   {
                       ciphertext[i] = a; // storing the special characters as it is.
                   }
               else // sees wheter the coresponding index , now stored in a is a part of the alphabet, returns non zero integers if true
               {
                   if (isupper(a) == 0 ) //sees whether the index is upper case character, returns 0 if no
                   {
                       int c = a;  // storing a in c, such that a does not change
                       c -= 97; //converting ASCII value of block letters to Alphabetical index, ie , 0-25, so that they can get encrypted
                       c = (c + k) % 26; //encryption with key k
                       c += 97; //converting back to ASCII
                       ciphertext[i] = (char) c; //storing encrypted index in ciphertext
                   }

                   else //same story as above, checking and encrypting for lower case, and isupper returns a nonzero integer.
                   {
                       int b = a;
                       b -= 65;
                       b = (b + k) % 26;
                       b += 65;
                       ciphertext[i] = (char) b;
                   }
               }

           }
           printf("ciphertext: %s\n", ciphertext); //printing out ciphertext
           return 0; // Command to terminate the program at the right moment
       }
   }
}
char digit(char a) // program for seeing the value in a variable is a numbers or not, simple function
{
   if ((int) a == 48 || (int) a == 49 || (int) a == 50 || (int) a == 51 || (int) a == 52 || (int) a == 53 || (int) a == 54 || (int) a == 55 || (int) a == 56 || (int) a == 57)
   {
       return 'y';
   }
   else
   {
       return 'n';
   }
}

char digitchecker(string a) // sees whether the charcter is a string are numbers or not
{
   int j  = strlen(a); // stores the string length as an integer
   int f = 0; // acts as a external counter for the number of 'y's
   for (int i  = 0; i < j; i++) // loop to check
   {
       char b = a[i]; // stores the value
       if ( digit(b) == 'n') // checks if its a number
       {
           break; // terminates loop if there is a non-number
       }
       else
       {
           f++; // increases the external counter
       }
   }
   if ( f == j) // this means that all the characters in the string are numbers
   {
       return 'y';
   }
   else // all characters where not numbers
   {
       return 'n';
   }

}

Check50 Results:

Results for cs50/problems/2020/x/caesar generated by check50 v3.0.10
:) caesar.c exists.
:) caesar.c compiles.
:( encrypts "a" as "b" using 1 as key
    output not valid ASCII text
:) encrypts "barfoo" as "yxocll" using 23 as key
:) encrypts "BARFOO" as "EDUIRR" using 3 as key
:) encrypts "BaRFoo" as "FeVJss" using 4 as key
:) encrypts "barfoo" as "onesbb" using 65 as key
:( encrypts "world, say hello!" as "iadxp, emk tqxxa!" using 12 as key
    output not valid ASCII text
:) handles lack of key
:) handles non-numeric key
:) handles too many arguments

Error Details

:( encrypts "a" as "b" using 1 as key
output not valid ASCII text
Log
running ./caesar 1...
sending input a...
checking for output "ciphertext: b\n"...


:( encrypts "world, say hello!" as "iadxp, emk tqxxa!" using 12 as key
output not valid ASCII text
Log
running ./caesar 12...
sending input world, say hello!...
checking for output "ciphertext: iadxp, emk tqxxa!\n"...

Running both the error plaintext separately gives the required output

~/caesar/ $ ./caesar 1
Plaintext: a
ciphertext: b

~/caesar/ $ ./caesar 12
Plaintext: world, say hello!
ciphertext: iadxp, emk tqxxa!
2

I ran your code and got something different than what you posted. After further checking, I found that the results are actually unpredictable. The code may or may not print extra characters after processing the plaintext, depending on what was left in memory from prior activity.

Here's the problem. The code encodes each char and stores it in ciphertext[]. Then it prints out ciphertext. Unfortunately, ciphertext is only long enough to hold the encoded characters. It doesn't have room for the end of string marker, '\0', and the EOS marker was never added to ciphertext. That means that printf won't know where to stop printing, so it prints whatever follows, until it encounters something that it thinks is the EOS marker, a byte that contains 0x00.

Modify the code to add the end of string marker and you'll cure the problem.

If this answers your question, please click on the check mark to accept. Let's keep up on forum maintenance. ;-)

3
  • OK will try it out!! May 16 '20 at 4:25
  • Yes, it worked out completely fine! But I do have some questions though.. Isn't the final process of adding '\0' automatic? how did you figure it out? Also, how do you figure ou errors like this which are not logical or compiler errors? May 16 '20 at 4:41
  • I was getting the same problem and I modified my code to add the end of string marker, '\0', as you suggested, and it worked. I was able to successfully submit my assignment. Thanks for all your help. Nov 2 '20 at 17:38

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .