Skip to content

Instantly share code, notes, and snippets.

@teeschorle
Last active July 29, 2021 11:28
Show Gist options
  • Save teeschorle/cc998f1ef47e270282d3d4fa3d217d31 to your computer and use it in GitHub Desktop.
Save teeschorle/cc998f1ef47e270282d3d4fa3d217d31 to your computer and use it in GitHub Desktop.
CS50 Problem Set 2 (Fall 2019) - Substitution
//CS50 Problem Set 2 (Fall 2019): Substitution
//Author: teeschorle
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
bool validate(string key);
int main(int argc, string argv[])
{
if (argc == 2)
{
string key = argv[1];
if (validate(key) == true)
{
string plaintext = get_string("plaintext: ");
int charcount = strlen(plaintext);
char ciphertext[charcount];
string abc = "abcdefghijklmnopqrstuvwxyz";
for (int i = 0; i < charcount; i++)
{
if (isupper(plaintext[i]) != 0)
{
for (int j = 0; j < 26; j++)
{
if(abc[j] == tolower(plaintext[i]))
{
ciphertext[i] = toupper(key[j]);
break;
}
}
}
else if (islower(plaintext[i]) != 0)
{
for (int j = 0; j < 26; j++)
{
if(abc[j] == plaintext[i])
{
ciphertext[i] = tolower(key[j]);
break;
}
}
}
else
{
ciphertext[i] = plaintext[i];
}
}
printf("ciphertext: %s\n", ciphertext);
return 0;
}
else
{
printf("Please make sure your key is a permutation of all 26 characters - not more, not less.\n");
return 1;
}
}
else
{
printf("Input error. Please provide a single key.\n");
return 1;
}
}
bool validate(string key)
{
int matches = 0;
if (strlen(key) == 26)
{
for (char c = 'a'; c <= 'z'; c++)
{
for (int i = 0; i < 26; i++)
{
if(tolower(key[i]) == c)
{
matches++;
break;
}
}
}
if(matches == 26)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
@GnvSaikiran
Copy link

check if you returned false for loop.
you have to return it out of the for loop.

@vietbuiminh
Copy link

Easy fix just minus 1 at the char ciphertext[length -1];

@theelectricmonk
Copy link

Your solution is more elegant that mine although mine compiles just fine. I would've assumed that printf wouldn't correctly print your char array because it's not null-terminated but I tried compiling and testing yours and it works fine. Odd.

@ayanika02
Copy link

After using check50, they are showing me the these-
:( encrypts "A" as "Z" using ZYXWVUTSRQPONMLKJIHGFEDCBA as key
output not valid ASCII text
:( encrypts "a" as "z" using ZYXWVUTSRQPONMLKJIHGFEDCBA as key
output not valid ASCII text
:( encrypts "ABC" as "NJQ" using NJQSUYBRXMOPFTHZVAWCGILKED as key
output not valid ASCII text
:( encrypts "XyZ" as "KeD" using NJQSUYBRXMOPFTHZVAWCGILKED as key
output not valid ASCII text
but on running the code, I am getting the desired output for each of them.
then why is it showing "output not valid ASCII code" ?

@owenmcurran
Copy link

After using check50, they are showing me the these-
:( encrypts "A" as "Z" using ZYXWVUTSRQPONMLKJIHGFEDCBA as key
output not valid ASCII text
:( encrypts "a" as "z" using ZYXWVUTSRQPONMLKJIHGFEDCBA as key
output not valid ASCII text
:( encrypts "ABC" as "NJQ" using NJQSUYBRXMOPFTHZVAWCGILKED as key
output not valid ASCII text
:( encrypts "XyZ" as "KeD" using NJQSUYBRXMOPFTHZVAWCGILKED as key
output not valid ASCII text
but on running the code, I am getting the desired output for each of them.
then why is it showing "output not valid ASCII code" ?

Could you link me to your code? I can't tell what the problem is just by the error messages

@ayanika02
Copy link

@ipskee
Copy link

ipskee commented Jul 5, 2020

Hey, thanks for the post
I am having a set of mistakes when I run the check50 on my code which I spend the last 3 hours trying to figure out but nothing..
I was checking your solution here and it's fundamentally same as mine, and that was even more troubling! so I copied and run your own code and got the exact same problems :/ please someone explain:

Results for cs50/problems/2020/x/substitution generated by check50 v3.0.10
:) substitution.c exists
:) substitution.c compiles
:( encrypts "A" as "Z" using ZYXWVUTSRQPONMLKJIHGFEDCBA as key output not valid ASCII text :( encrypts "a" as "z" using ZYXWVUTSRQPONMLKJIHGFEDCBA as key output not valid ASCII text :( encrypts "ABC" as "NJQ" using NJQSUYBRXMOPFTHZVAWCGILKED as key output not valid ASCII text :( encrypts "XyZ" as "KeD" using NJQSUYBRXMOPFTHZVAWCGILKED as key output not valid ASCII text
:) encrypts "This is CS50" as "Cbah ah KH50" using YUKFRNLBAVMWZTEOGXHCIPJSQD as key
:) encrypts "This is CS50" as "Cbah ah KH50" using yukfrnlbavmwzteogxhcipjsqd as key
:) encrypts "This is CS50" as "Cbah ah KH50" using YUKFRNLBAVMWZteogxhcipjsqd as key
:) encrypts all alphabetic characters using DWUSXNPQKEGCZFJBTLYROHIAVM as key
:) handles lack of key
:) handles invalid key length
:) handles invalid characters in key
:) handles duplicate characters in key
:) handles multiple duplicate characters in key

If anyone is struggling with this like I did, its highly likely that we created this "ciphertext" been working differently as we expected.
if you recall from the lecture, all string has an char of '\0' at the end of it. If we loop through our plaintext and 'append'/put the ciphered character into this new array, you would need to add '\0' at ciphertext[strlen(plaintext)] to finish up the string. Or i guess something to do with the memory structure, it will add random chars at the end of the operations.

In short: add the extra char '\0' at the end of your ciphered text.

@rksoni11
Copy link

include <stdio.h>

include <cs50.h>

include <string.h>

include <ctype.h>

bool check(string key);

int main(int argc, string argv[])
{
if (argc == 2)
{

    string key = argv[1];

    if (check(key) == true)
    {

        string text = get_string("Enter plaintext : ");

        int textlenth = strlen(text);

        char cipher[textlenth];

        string alpha = "abcdefghijklmnopqrstuvwxyz";

        for (int j = 0; j < textlenth; j++)
        {
            if (isupper(text[j]) != 0)
            {
                for (int k = 0; k < 26; k++)
                {
                    if (alpha[k] == tolower(text[j]))
                    {
                        cipher[j] = toupper(key[k]);
                        break;
                    }
                }
            }
            else if (islower(text[j]) != 0)
            {
                for (int k = 0; k < 26; k++)
                {
                    if (alpha[k] == text[j])
                    {
                        cipher[j] = tolower(key[k]);
                        break;
                    }
                }
            }
            else
            {
                cipher[j] = text[j];
            }

        }

        cipher[textlenth] = '\0';

        printf("ciphertext: %s\n", cipher);

        return 0;
    }
    else
    {
        printf("Usage: ./substitution key\n");
        return 1;
    }
}
else
{
    printf("Usage: ./substitution key\n");
    return 1;
}

}

bool check(string key)
{
int same = 0;

if (strlen(key) == 26)
{
    for (char c = 'a'; c <= 'z'; c++)
    {
        for (int n = 0 ; n < 26; n++)
        {
            if (tolower(key[n]) == c)
            {
                same++;
                break;
            }
        }
    }

    if (same == 26)
    {
        return true;
    }
    else
    {
        return false;
    }
}
else
{
    return false;
}

}

@alex-battikha
Copy link

alex-battikha commented Aug 6, 2020

Hi all,

I am writing this to help all of those who ran into a similar issue with the code not passing all test cases and returning random characters at the end. This is because we are dealing with adding chars to a new array and returning that new array as a string. Recall from the lectures that a string ends with '\0' so the code does not pass all cases because it's returning as a string of chars but no '\0'

Please find code attached for your reference

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

bool validate(string key);

int main(int argc, string argv[])
{
    if (argc == 2)
    {
        string key = argv[1];
        if(validate(key) == true)
        {
            string plaintext = get_string("plaintext: ");
            int charcount = strlen(plaintext);
            char ciphertext[charcount];
            string abc = "abcdefghijklmnopqrstuvwxyz";
            for(int i = 0; i < charcount; i++)
            {
                if(isupper(plaintext[i]) != 0)
                {
                    for(int j = 0; j < 26; j++)
                    {
                        if(abc[j] == tolower(plaintext[i]))
                        {
                             ciphertext[i] = toupper(key[j]);
                            break;
                        }
                    }
                }
                else if(islower(plaintext[i])!=0)
                {
                    for(int j = 0; j < 26; j++)
                    {
                        if (abc[j] == plaintext[i])
                        {
                            ciphertext[i] = tolower(key[j]);
                            break;
                        }
                    }
                }
                else
                {
                    ciphertext[i] = plaintext[i];
                }
            }
            ciphertext[charcount] = '\0';
            
            printf("ciphertext: %s\n", ciphertext);
            
            return 0;
        }
        else
        {
            printf("Please make sure your key is a permutation of all 26 characters - not more, not less.\n");
            return 1;
        }
    }
    else
    {
        printf("Input error. Please provide a key.");
        return 1;
    }
    
}

bool validate(string key)
{
    int matches = 0;
    if (strlen(key) == 26)
    {
        for (char c = 'a'; c <= 'z'; c++)
        {
            for (int i = 0; i < 26; i++)
            {
                if(tolower(key[i]) == c)
                {
                    matches++;
                    break;
                }
            }
        }
        if(matches == 26)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}

@aldeghericongh
Copy link

include <stdio.h>

include <cs50.h>

include <string.h>

include <ctype.h>

bool check(string key);

int main(int argc, string argv[])
{
if (argc == 2)
{

    string key = argv[1];

    if (check(key) == true)
    {

        string text = get_string("Enter plaintext : ");

        int textlenth = strlen(text);

        char cipher[textlenth];

        string alpha = "abcdefghijklmnopqrstuvwxyz";

        for (int j = 0; j < textlenth; j++)
        {
            if (isupper(text[j]) != 0)
            {
                for (int k = 0; k < 26; k++)
                {
                    if (alpha[k] == tolower(text[j]))
                    {
                        cipher[j] = toupper(key[k]);
                        break;
                    }
                }
            }
            else if (islower(text[j]) != 0)
            {
                for (int k = 0; k < 26; k++)
                {
                    if (alpha[k] == text[j])
                    {
                        cipher[j] = tolower(key[k]);
                        break;
                    }
                }
            }
            else
            {
                cipher[j] = text[j];
            }

        }

        cipher[textlenth] = '\0';

        printf("ciphertext: %s\n", cipher);

        return 0;
    }
    else
    {
        printf("Usage: ./substitution key\n");
        return 1;
    }
}
else
{
    printf("Usage: ./substitution key\n");
    return 1;
}

}

bool check(string key)
{
int same = 0;

if (strlen(key) == 26)
{
    for (char c = 'a'; c <= 'z'; c++)
    {
        for (int n = 0 ; n < 26; n++)
        {
            if (tolower(key[n]) == c)
            {
                same++;
                break;
            }
        }
    }

    if (same == 26)
    {
        return true;
    }
    else
    {
        return false;
    }
}
else
{
    return false;
}

}

Thanks! This really help me out this problem

Copy link

ghost commented Sep 8, 2020

those answers are so long and complicated. Here is my solution:

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

bool check (string s);
bool check (string s)
{
int j, j2;
if (strlen(s) != 26)
{
return false;
}
for (j = 0; j < strlen(s); ++j)
{
for (j2 = j + 1; j2 < strlen(s); ++j2)
{
if (s[j]==s[j2])
{
return false;
}
}
}
for (j = 0; j < strlen(s); ++j)
{
if (isalpha(s[j])==0)
{
return false;
}
}
return true;
}
int main(int c5, string v[])
{
if (c5 != 2)
{
printf ("Wrong Input type. Exp: ./subtitution VcHpRzGjNtLsKfBdQwAxEuYmOi\n");
return 1;
}
int sl = strlen(v[1]);
string cr = v[1];
if (check(v[1])==true)
{
char carr [2][26], c2 [] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (int j = 0; j<26;++j)
{
carr[0][j] = cr[j];
carr[1][j] = c2[j];
}
string p2 = get_string("Plain Text: ");
string p3=p2;
int b = 0;
for (;b<strlen(p2); ++b)
{
for (int g = 0; g<26; ++g)
{
if (p2[b] == tolower(carr[1][g]))
{
p3[b] = tolower(carr[0][g]);
break;
}
else if (p2[b] == carr[1][g])
{
p3[b] = toupper((carr[0][g]));
break;
}
else
p3[b] = p2[b];
}
}
printf ("ciphertext: %s\n", p3);
}
else
{
printf ("Key must contain 26 characters.\n");
return 1;
}
}`

@ashishejale
Copy link

Since every one is posting their codes here I thought why not do the same. If some one reads this, please critique on my code so I get better at coding. thankyou :)

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

string ciphertext(string plain, string key);

int main(int argc, string argv[])
{
//To check if arguments are 2 and numeric
if (argc == 2)
{
string key = (argv[1]);
if (strlen(key) == 26) //To check key length
{

        printf("%s\n", key);

        for (int i = 0; (key[i]) != '\0'; i++)
        {
            if (isdigit(key[i])) //To check if key conatains digit
            {
                printf("Key must only cntain alphabetic characters.\n");
                return 1;
            }

            if (isalpha(key[i])) //To check if key is alphabetical //To check if alphabet is double in key
            {
                for (int j = i + 1; key[j] != '\0'; j++)
                {
                    if (key[i] == key[j])
                    {
                        printf("Key must not contain repeated characters.\n");
                        return 1;
                    }
                }
            }
        }
        //main code
        string plain = get_string("plaintext:");
        string cipher = ciphertext(plain, key); //calling function to cipher
        printf("ciphertext: %s\n", cipher);
        return 0;
    }
    else //To check length of key
    {
        printf("Key must contain 26 characters.\n");
        return 1;
    }
}
if (argc != 2) //To check if arguments are 2
{
    printf("Usage: ./substitution key\n");
    return 1;
}

}

string ciphertext(string plain, string key)
{
string c = plain;
string k = key;
string abc = "abcdefghijklmnopqrstuvwxyz";

for (int i = 0; plain[i] != '\0'; i++)
{
    if (islower(plain[i]) != 0)
    {
        for (int j = 0; k[j] != '\0'; j++)
        {
            if (abc[j] == (plain[i]))
            {
                c[i] = tolower(k[j]);
                break;
            }
        }
    }
    else if (isupper(plain[i]) != 0)
    {
        for (int j = 0; k[j] != '\0'; j++)
        {
            if (toupper(abc[j]) == plain[i])
            {
                c[i] = toupper(k[j]);
                break;
            }
        }
    }
    else
    {
        c[i] = plain[i];

    }
}
return c;

}

Copy link

ghost commented Feb 6, 2021

This function returns a non-zero int if c is an uppercase letter and 0 if c is not an uppercase letter.

@M-Ali-Horya
Copy link

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

int main(int argc, string argv[])
{
if (argc != 2 || !isalpha(*argv[1]))
{
printf("Usage: ./sub key\n");
return (1);
}
string key = argv[1];
if (strlen(key) != 26)
{
printf("Usage: ./sub key\n");
return (1);
}
string s = get_string("Plaintext: ");
printf("Ciphertext: ");
for (int i = 0, n = strlen(s); i < n; i++)
{
if (isupper(s[i]))
{
char u = s[i];
char m = 'A';
if (islower(s[i]))
m = 'a';
printf("%c",key[u - m] );
}
else
{
printf("%c",s[i]);
}
}
printf("\n");
return(0);
}

@nickiliopoulosedu
Copy link

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

bool validate_key(string key);

int main(int argc, string argv[])
{
    //checks if key is the right length
    if (argc != 2 || strlen(argv[1]) != 26 || validate_key((string) argv[1]) != 1)
    {
        printf("Key must exist and contain 26 non identical alphabetical characters.\n");
        return 1;
    }

    //gets input text

    string text = get_string("plaintext: ");

    int len = strlen(text);
    char mychar = toupper(text[0]) - 65;
    for (int i = 0; i < len; i++)
    {
        if (mychar >= 0 && mychar <= 26)
        {
            if (isupper(text[i]))
            {
                text[i] = toupper((char) argv[1][(int) mychar]);
            }
            else
            {
                text[i] = tolower((char) argv[1][(int) mychar]);
            }
        }
        mychar = toupper(text[i + 1]) - 65;
    }

    printf("ciphertext: %s\n", text);
    return 0;
}

bool validate_key (string key)
{
    int len = strlen(key);
    char mychar;
    for(int i = 0; i < len; i++)
    {
        mychar = toupper(key[i]);
        if(mychar >= 65 && mychar <= 90)
        {
            for(int j = i + 1; j < len; j++)
            {
                if(mychar == toupper(key[j]))
                {
                    return 0;
                }
            }
        }
        else
        {
            return 0;
        }
    }
    return 1;
}

@Jaga26
Copy link

Jaga26 commented Jul 29, 2021

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

//get the input from the user in comomand-line
int main (int argc, string argv[])
{
if (argc == 2) // Checks if it is two arugument including file name
{
int len = strlen(argv[1]);

    for (int i = 0; i < len; i++)        //          Checks if it is a digit, if yes, then print the following
    {
        if (isdigit(argv[1][i]))
        {
            printf("Usage: ./substitution key \n");
            exit(0);        //                          To terminate the program immediately
        }
    }
    if (len != 26)       //                          Checks if the length of the given input in command-line is 26 characters, if not, then print
    {
        printf("key must contain 26 characters.");
    }

    string plain = get_string("Plain text: ");      //Get plain text from the user to encode it

    string cipher;
    printf("Cipher text: ");

    for (int i = 0, n = strlen(plain); i < n; i++)
    {
        if (islower(plain[i]))      //              Checks the case sensitive
        {
            printf("%c", tolower(argv[1][plain[i] - 'a'])); // prints lower case cipher calue
        }
        else if (isupper(plain[i]))
        {
            printf("%c", toupper(argv[1][plain[i] - 'A'])); //prints upper case cipher value
        }
        else
        {
            printf("%c", plain[i]);             //          prints apart from alphabetical characters
        }
    }
}

else
{
    printf("Usage: ./substitution key");
}

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment