Skip to content

Instantly share code, notes, and snippets.

@teeschorle
Last active July 29, 2021 11:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • 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;
}
}
@Nour-x
Copy link

Nour-x commented May 20, 2020

thanks Owen!
here's my code (I also tried to run the code above and got the same output)
P.S. I don't know why only a part of the code is previewed as a code, sorry I tried

` #include <stdio.h>
#include <cs50.h>
#include <string.h>
//for character classification functions
#include <ctype.h>

//function declaration
bool validate(string key);

//global variable
string abc = "abcdefghijklmnopqrstuvwxyz";

int main(int argc, string argv[])
{
if (argc == 2)
{
string key = argv [1];
if (validate(key) == true)
{

        string plaintext = get_string("plaintext: ");
        int length = strlen (plaintext);
        char ciphertext[length];

        for (int i = 0; i < length; 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("Key must contain 26 unique characters\n");
        return 1;
    }

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

}

bool validate(string key)
{
int match_counter = 0;
if (strlen(key) == 26)
{
for (int i = 0; i < 26; i++)
{
for (int j = 0; j < 26; j++)
{
if (tolower(key[j]) == abc[i])
{
match_counter++;
break;
}
}
}
if (match_counter == 26)
{
return true;
}
return false;
}
return false;

}
`

@ElMehdiElazhary
Copy link

Hello, I'm still new to this and I had a silly question. How does the built function (validate) work?

@owenmcurran
Copy link

Sorry for the slow reply, I've been busy the last few days and haven't got much of a chance to turn on my computer. So I looked over your code and I think I know what your problem is. I did some slight reformatting of your code to make it more readable, you'll see what changes I made from the comments I left. Basically what the problem is is that you're generating a segmentation fault (http://web.mit.edu/10.001/Web/Tips/tips_on_segmentation.html) when copying your arrays. When you're using the isupper and islower functions all that they do is return true or false for the particular case. I'm not an expert on C by any means but I think you need to redo the code for how you're checking for which case the given values are in. I've linked below the copy of your code and my code so you can see how we're handling them differently. Sorry I couldn't do more testing and figure everything out I'm just back to work so time is pretty short. I'm off for the next few days so if you're still stuck let me know and I'll be happy to help you even further if you need it! Happy learning.

Your code: https://pastebin.com/dG42BY2U
My code: https://pastebin.com/GgKiicka

@owenmcurran
Copy link

Hello, I'm still new to this and I had a silly question. How does the built function (validate) work?

So basically it starts at the letter a and loops through every letter in the key, if the key contains 'a' in this case, it increments the counter variable, matches by 1. After going through all the alphabet (a-z), it checks that the matches variable has been incremented 26 times i.e the key contains all 26 letters and no duplicates. If there was a duplicate, for example, if c was in the key twice the loop would find the first c and increment matches, then move on to the next letter, as the break statement ends the loop once the first match has been found and you'd be left with a matches variable that's equal to 25 so you'd return false. If all letters are found once and only once it returns true to show everything is in order. Let me know if you're unsure of anything else, check my code in the comment above if you need some more ideas of what to do, the comments on it should help. If you get stuck feel free to ask, we've all got to start somewhere friend. Happy coding!

@Nour-x
Copy link

Nour-x commented May 22, 2020

Sorry for the slow reply, I've been busy the last few days and haven't got much of a chance to turn on my computer. So I looked over your code and I think I know what your problem is. I did some slight reformatting of your code to make it more readable, you'll see what changes I made from the comments I left. Basically what the problem is is that you're generating a segmentation fault (http://web.mit.edu/10.001/Web/Tips/tips_on_segmentation.html) when copying your arrays. When you're using the isupper and islower functions all that they do is return true or false for the particular case. I'm not an expert on C by any means but I think you need to redo the code for how you're checking for which case the given values are in. I've linked below the copy of your code and my code so you can see how we're handling them differently. Sorry I couldn't do more testing and figure everything out I'm just back to work so time is pretty short. I'm off for the next few days so if you're still stuck let me know and I'll be happy to help you even further if you need it! Happy learning.

Your code: https://pastebin.com/dG42BY2U
My code: https://pastebin.com/GgKiicka

Thanks a lot! the comments are really helpful
I'll read more about the segmentation fault and try understand what's going wrong with my code.
Good luck with your work, and have a good day

@devonxmurray
Copy link

Basically the problem was that there were garbage elements being printed but detected by check50 ( you can identify this by printing the cipher text within the loop that iterates through the plain text). This is due to not terminating the loop when it reaches the ntc(null terminating character). What i added breaks from the loop if the ntc is found and assigns the ntc to cipher text at the ith position(the end of the string of characters). The lines of code added are in the comments, this program should get full marks in check50 now...

#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";
// int i=0;
for (i = 0; i < charcount; i++)
{
// if (plaintext[i]=='\0')
// {
// break;
// }
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[i]='\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 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;
}
}

@morgan03
Copy link

Hi, I'm having a problem compiling my code. I keep on getting the error 'function definition is not allowed here', can anyone help me please?

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

bool is_valid_key(string s);

int main(int argc, string argv[])
{
// Command Line arguments
if (argc != 2)
{
printf("Usage: ./substitution key");
return 1;
}

if (!is_valid_key(argv[1]))
{
    printf("Key must contain 26 characters\n");
    return 1;
}

string s = get_string("plaintext:\n");
string difference = argv[1];

for(int i = 'A'; i <= 'Z'; i++)
    difference[i - 'A'] = toupper(difference [i - 'A']) - i;
printf("ciphertext: ");

for(int i = 0, len = strlen(s); i < len; i++)
{
    if(isalpha(s[i]))
        s[i] = s[i] + difference[s[i] - (isupper(s[i]) ? 'A' : 'a')];
        printf("%c", s[i]);

}
printf("\n");

bool is_valid_key(string s)
{
int len = strlen(s);
if(len != 26)
return false;

int freq[26] = { 0 };
for(int i = 0; i < len; i++)
{
    if (!isalpha(s[i]))
        return false;
    int index = toupper(s[i]) - 'A';
    if (freq[index] > 0)
        return false;
    freq[index]++;
}
return true; }

}

@alexjaffe
Copy link

Hello - thanks for sharing! this was my approach used similar logic, took me a bit more code. This is my first time programming so comparing solutions has been helpful. I tried using the isupper and was getting variable errors - now makes sense on the int value is 0 / false.

Available below for reference, included comments too.

//
Program that enciphers any text input using a key of 26 alphabetical characters.
The key is input as a command line argument and returns 1 with instructions for any invalid keys.
*/

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

//Command line argument that launches with KEY
int main(int argc, string argv[])
{
//reject all input that is not a single string with the key
if (argc != 2)
{
printf("Usage: ./substitution KEY");
return 1;
}
//assigns argv to a string to create length
string key = "";
key = argv[1];

//reject all KEYs that are not 26 characters in length
int key_length = strlen(key);
if (key_length != 26)
{
    printf("Key must contain 26 characters.\n");
    return 1;
}

//runs a loop that checks every character
for (int i = 0; i < key_length; i++)
{
    //checks for if any character is not an alphabetical number, isalpha pulls from the ctype library
    if (isalpha(key[i]) == false)
    {
        printf("Key must only contain alphabetic characters. \n");
        return 1;
    }
    //runs a loop that starts with a letter, and then compares against all letters following it, rejects if the character is repeated
    for (int j = (i + 1); j < (key_length - i); j++)
    {
        if ((key[i] == key[j]) || (toupper(key[i]) == key[j]) || (tolower(key[i]) == key[j]))
        {
            printf("Key must not contain repeated characters. \n");
            return 1;
        }
    }
}

//prompts the user to input a string into the program
string plaintext = get_string("plaintext:  ");

//creates two arrays one that has all uppercase letters of the key, second has all lowercase
char key_upper[key_length];
char key_lower[key_length];
for (int i = 0; i < key_length; i++)
{
    if (key[i] >= 'a' && key[i] <= 'z')
    {
        key_upper[i] = key[i] - 32;
    }
    else
    {
        key_upper[i] = key[i];
    }

    if (key[i] >= 'A' && key[i] <= 'Z')
    {
        key_lower[i] = key[i] + 32;
    }
    else
    {
        key_lower[i] = key[i];
    }
}

//encipher ode that takes the plaintext input, and outputs the ciphertext
//runs through a loop that compares the plaintext char to the letter of alphabet until it matches and assigns array #
//once matched it assigns the array #, and then assigns the cipher text the value of key at that array #
//because we are 'case agnostic' we have the if statement, working for both uppercase and lowercase
//we do not assign a value from the key for non alphabetical characters

int plaintext_length = strlen(plaintext);
char alpha_upper[26] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
char alpha_lower[26] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
int alpha_length = (sizeof(alpha_upper) / sizeof(*alpha_upper));
//for ciphertext we are adding an extra value to place a null value at the end
char ciphertext[plaintext_length + 1];

for (int i = 0; i < plaintext_length; i++)
{
    if (plaintext[i] >= 'A' && plaintext[i] <= 'Z')
    {
        int upper_char = 0;
        for (int y = 0; y < alpha_length; y++)
        {
            if (plaintext[i] == alpha_upper[y])
            {
                upper_char = y;
            }
        }
        ciphertext[i] = key_upper[upper_char];
    }
    else if (plaintext[i] >= 'a' && plaintext[i] <= 'z')
    {
        int lower_char = 0;
        for (int y = 0; y < alpha_length; y++)
        {
            if (plaintext[i] == alpha_lower[y])
            {
                lower_char = y;
            }
        }
        ciphertext[i] = key_lower[lower_char];
    }
    else
    {
        ciphertext[i] = plaintext[i];
    }
}
//to printf the array, we need to assign the null value at the end of char
ciphertext[plaintext_length] = '\0';
printf("ciphertext: %s\n", ciphertext);
return 0;

}

@owenmcurran
Copy link

Hi, I'm having a problem compiling my code. I keep on getting the error 'function definition is not allowed here', can anyone help me please?

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

bool is_valid_key(string s);

int main(int argc, string argv[])
{
// Command Line arguments
if (argc != 2)
{
printf("Usage: ./substitution key");
return 1;
}

if (!is_valid_key(argv[1]))
{
    printf("Key must contain 26 characters\n");
    return 1;
}

string s = get_string("plaintext:\n");
string difference = argv[1];

for(int i = 'A'; i <= 'Z'; i++)
    difference[i - 'A'] = toupper(difference [i - 'A']) - i;
printf("ciphertext: ");

for(int i = 0, len = strlen(s); i < len; i++)
{
    if(isalpha(s[i]))
        s[i] = s[i] + difference[s[i] - (isupper(s[i]) ? 'A' : 'a')];
        printf("%c", s[i]);

}
printf("\n");

bool is_valid_key(string s)
{
int len = strlen(s);
if(len != 26)
return false;

int freq[26] = { 0 };
for(int i = 0; i < len; i++)
{
    if (!isalpha(s[i]))
        return false;
    int index = toupper(s[i]) - 'A';
    if (freq[index] > 0)
        return false;
    freq[index]++;
}
return true; }

}

So your problem is you have your is_valid_key function enclosed within the curly braces of your main function. I fixed up your code here to fix that problem and it compiles no problem but I didn't get time to test it.

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

bool is_valid_key(string s);

int main(int argc, string argv[])
{
    // Command Line arguments
    if (argc != 2)
    {
        printf("Usage: ./substitution key");
        return 1;
    }

    if (!is_valid_key(argv[1]))
    {
        printf("Key must contain 26 characters\n");
        return 1;
    }

    string s = get_string("plaintext:\n");
    string difference = argv[1];

    for(int i = 'A'; i <= 'Z'; i++)
    {
        difference[i - 'A'] = toupper(difference [i - 'A']) - i;
        printf("ciphertext: ");
    }

    for(int i = 0, len = strlen(s); i < len; i++)
    {
    if(isalpha(s[i]))
        s[i] = s[i] + difference[s[i] - (isupper(s[i]) ? 'A' : 'a')];
        printf("%c", s[i]);
    }
    printf("\n");
}

bool is_valid_key(string s)
{
    int len = strlen(s);
    if(len != 26)
    return false;

    int freq[26] = { 0 };
    for(int i = 0; i < len; i++)
    {
        if (!isalpha(s[i]))
        {
            return false;
        }
        int index = toupper(s[i]) - 'A';
        if (freq[index] > 0)
        {
            return false;
        }
    freq[index]++;
    }
    return true; 
}

@owenmcurran
Copy link

Hello - thanks for sharing! this was my approach used similar logic, took me a bit more code. This is my first time programming so comparing solutions has been helpful. I tried using the isupper and was getting variable errors - now makes sense on the int value is 0 / false.

Available below for reference, included comments too.

//
Program that enciphers any text input using a key of 26 alphabetical characters.
The key is input as a command line argument and returns 1 with instructions for any invalid keys.
*/

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

//Command line argument that launches with KEY
int main(int argc, string argv[])
{
//reject all input that is not a single string with the key
if (argc != 2)
{
printf("Usage: ./substitution KEY");
return 1;
}
//assigns argv to a string to create length
string key = "";
key = argv[1];

//reject all KEYs that are not 26 characters in length
int key_length = strlen(key);
if (key_length != 26)
{
    printf("Key must contain 26 characters.\n");
    return 1;
}

//runs a loop that checks every character
for (int i = 0; i < key_length; i++)
{
    //checks for if any character is not an alphabetical number, isalpha pulls from the ctype library
    if (isalpha(key[i]) == false)
    {
        printf("Key must only contain alphabetic characters. \n");
        return 1;
    }
    //runs a loop that starts with a letter, and then compares against all letters following it, rejects if the character is repeated
    for (int j = (i + 1); j < (key_length - i); j++)
    {
        if ((key[i] == key[j]) || (toupper(key[i]) == key[j]) || (tolower(key[i]) == key[j]))
        {
            printf("Key must not contain repeated characters. \n");
            return 1;
        }
    }
}

//prompts the user to input a string into the program
string plaintext = get_string("plaintext:  ");

//creates two arrays one that has all uppercase letters of the key, second has all lowercase
char key_upper[key_length];
char key_lower[key_length];
for (int i = 0; i < key_length; i++)
{
    if (key[i] >= 'a' && key[i] <= 'z')
    {
        key_upper[i] = key[i] - 32;
    }
    else
    {
        key_upper[i] = key[i];
    }

    if (key[i] >= 'A' && key[i] <= 'Z')
    {
        key_lower[i] = key[i] + 32;
    }
    else
    {
        key_lower[i] = key[i];
    }
}

//encipher ode that takes the plaintext input, and outputs the ciphertext
//runs through a loop that compares the plaintext char to the letter of alphabet until it matches and assigns array #
//once matched it assigns the array #, and then assigns the cipher text the value of key at that array #
//because we are 'case agnostic' we have the if statement, working for both uppercase and lowercase
//we do not assign a value from the key for non alphabetical characters

int plaintext_length = strlen(plaintext);
char alpha_upper[26] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
char alpha_lower[26] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
int alpha_length = (sizeof(alpha_upper) / sizeof(*alpha_upper));
//for ciphertext we are adding an extra value to place a null value at the end
char ciphertext[plaintext_length + 1];

for (int i = 0; i < plaintext_length; i++)
{
    if (plaintext[i] >= 'A' && plaintext[i] <= 'Z')
    {
        int upper_char = 0;
        for (int y = 0; y < alpha_length; y++)
        {
            if (plaintext[i] == alpha_upper[y])
            {
                upper_char = y;
            }
        }
        ciphertext[i] = key_upper[upper_char];
    }
    else if (plaintext[i] >= 'a' && plaintext[i] <= 'z')
    {
        int lower_char = 0;
        for (int y = 0; y < alpha_length; y++)
        {
            if (plaintext[i] == alpha_lower[y])
            {
                lower_char = y;
            }
        }
        ciphertext[i] = key_lower[lower_char];
    }
    else
    {
        ciphertext[i] = plaintext[i];
    }
}
//to printf the array, we need to assign the null value at the end of char
ciphertext[plaintext_length] = '\0';
printf("ciphertext: %s\n", ciphertext);
return 0;

}

Looks really good, especially for a first time! Your formatting is great, love to see clean code like that. A few places you could have made things slightly more readable but they're really not a major concern. Should be proud, keep up the good work!

@morgan03
Copy link

Thanks for the help! Thanks to you the code does compile, but I noticed that I made a few errors that I shouldn't have a problem sorting out.

@owenmcurran
Copy link

Thanks for the help! Thanks to you the code does compile, but I noticed that I made a few errors that I shouldn't have a problem sorting out.

No problem at all, all the best with figuring out the problems. If you're stuck and can't figure out the problem let me know, always happy to help!

@morgan03
Copy link

Of course, thanks!

@GnvSaikiran
Copy link

My program is leaving an error message reading: "control may reach end of non-void function [-Werror,-Wreturn-type]"
Why is that?

If you could link me to your code I can do my best to help you out?

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

@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