Home > Blockchain >  Check50 "not a valid ASCII Ouput" on pset2 caesar
Check50 "not a valid ASCII Ouput" on pset2 caesar

Time:08-19

I completed the caesar assignment on cs50 and tested it on my terminal and it worked perfectly, but on check50 is kept failing some tests.

#include <ctype.h>
#include <string.h>
#include <math.h>
#include <stdio.h>

int getkey(string k);
string cipher(string s, int key);
int key;
int p;
int q;

int main(int argc, string argv[])
{
    // Allow 2 command line inputs
    if (argc == 2)
    {
        // Assign a local string to allow char scan
        string s = argv[1];

        // Check if all inputs are numbers
        for (int i = 0; s[i] != 0; i  )
        {
            if (s[i] < 48 || s[i] > 57)
            {
                printf("Usage: ./caesar key\n");
                return 1;
            }
        }
        // Get key from string
        int cipherkey = getkey(s);

        // Get user text
        string text = get_string("plaintext: ");

        // Calculate ciphertext and print
        string ciphertext = cipher(text, cipherkey);
        printf("ciphertext: %s\n", ciphertext);
    }
    else
    {
        printf("Usage: ./caesar key\n");
        return 1;
    }
}

// Change string to int. Turns out theres already a function for this called atoi()
int getkey(string k)
{
    key = 0;
    for(int i = 0, conv = 0, n = strlen(k); k[i] != 0; i  , n--)
    {
        // Calcute the placevalue
        p = pow(10, n-1);
        conv = k[i] - 48; // Convert to int
        key = key   (conv * p); // Sum up
    }
    return key % 26;
}

// Cipher text
string cipher (string s, int key)
{
    for(int i = 0; s[i] != 0; i  )
    {
       if(islower(s[i]))
       {
           s[i] = s[i]   key;
           while(s[i] > 122)
           {
               s[i] = (s[i] - 123)   97;
           }
       }
       else if(isupper(s[i]))
       {
           s[i] = s[i]   key;
           while(s[i] > 90)
           {
               s[i] = (s[i] - 91)   65;
           }
       }
    }
    return s;
}

with error message

:) caesar.c compiles.
:) encrypts "a" as "b" using 1 as key
:( encrypts "barfoo" as "yxocll" using 23 as key
    output not valid ASCII text
:) 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 argv[1]
:) handles non-numeric key
:) handles too many arguments

I wrote the code without knowing the "atoi" function so i implemented a function called getkey() to return key. when i returned key normally, it failed.

:( encrypts "barfoo" as "onesbb" using 65 as key
Output not a valid ASCII text

Until i returned key % 26;

I dont know why check50 isnt working although the program works well on my terminal. Please help.

Updated code:

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

string cipher(string s, int key);

int main(int argc, string argv[])
{
    // Allow 2 command line inputs
    if (argc == 2)
    {
        // Assign a local string to allow char scan
        string s = argv[1];

        // Check if all inputs are numbers
        for (int i = 0; s[i] != 0; i  )
        {
            if (s[i] < 48 || s[i] > 57)
            {
                printf("Usage: ./caesar key\n");
                return 1;
            }
        }
        // Get key from string
        int cipherkey = atoi(s);

        // Get user text
        string text = get_string("plaintext: ");

        // Calculate ciphertext and print
        string ciphertext = cipher(text, cipherkey);
        printf("ciphertext: %s\n", ciphertext);
    }
    else
    {
        printf("Usage: ./caesar key\n");
        return 1;
    }
}

// Cipher text
string cipher (string s, int key)
{
    for(int i = 0; s[i] != 0; i  )
    {
        if(islower(s[i]))
        {
            s[i] = (int) s[i]   key;
            while(s[i] > 'z')
            {
                s[i] = (s[i] - 123)   97;
            }
        }
        else if(isupper(s[i]))
        {
            s[i] = (int) s[i]   key;
            while(s[i] > 'Z')
            {
                s[i] = (s[i] - 91)   65;
            }
        }
    }
    return s;
}

CodePudding user response:

I've rewritten the function trying to avoid going to far making corrections and improvements. Now, the copy is actually unnecessary, but I hope it helps you understand that a "signed (8 bit) char" is not 'wide' enough to use in calculations that lead to overflow...

Please read the following and try to follow along.

string cipher( string s, int key ) {
    for( int i = 0; s[i] != '\0'; i   ) {
        if( !isalpha( s[i] ) )
            continue;

        int copy = (int)s[i]; // unnecessary casting, but...

        // transform ASCII value into 0-25 range
        if( islower( s[i] ) )
            copy = copy - 'a';
        else // must be uppercase
            copy = copy - 'A';

        copy = (copy   key) % 26;

        // transform enciphered MODULO back into ASCII char
        if( islower( s[i] ) )
            copy = copy   'a';
        else // must be uppercase
            copy = copy   'A';

        s[i] = copy;
    }

    return s;
}

Quiet night, so I thought I'd rewrite the rewrite just to see what it looked like...

string cipher( string s, int key ) {
    for( char *cp = s; *cp; cp   )
        if( isalpha( *cp ) ) {
            char c = "Aa"[ !!islower(*cp) ];
            *cp = (char)(((*cp - c   key) % 26)   c);
        }
    return s;
}
  • Related