substitution cs50 - handle repeating characters in key - c

This code is for the CS50 Harvard course Pset 2 substitution.
one section of my program requires a check on the key to make sure characters are not repeated. I am failing this check as it reads ' :( Handles duplicate characters in Key - timed out while waiting for program to exit'
What needs to be fixed in my code to pass this final check?
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, string argv[])
{
printf("\n");
//check if we have correct number of command line arguments
if (argc != 2)
{
printf("Usage: ./substitution key\n");
printf("(Please enter only 2 command line arguments)\n");
return 1; //error
}
//initialize global variables for use//
//length of key
int s = strlen(argv[1]);
//copy of key may be altered if it is not valid yet
string k = argv[1];
// if else to check if our key is 26 characters
if (s == 26)
{
for (int i = 0; i < 26; i++)
{
//checks each index in k to see if it is alpha or not, throws error if not
if (!isalpha(k[i]))
{
printf("Usage: ./substitution key\n");
printf("(Key must be alphabetical)\n");
return 1; //error
}
}
for (int i = 0; i < s; i++)
{
for (int j = i + 1; j < s; j++)
{
if (isupper(k[i]))
{
k[i] = tolower(k[i]);
}
if (k[i] == k[j])
{
printf("Usage: ./substitution key\n");
printf("(Key can not have repeating characters)\n");
return 1; //error
}
}
}
}
else
{
//if we dont have 26 characters
printf("Usage: ./subsitution key\n");
printf("Key must be 26 characters\n");
return 1;
}
//true key for our cipher
string key = k;
//ask user for plaintext
string plaintext = get_string("Plaintext: ");
int n = strlen(plaintext);
printf("ciphertext: ");
char *ciphertext = malloc(n);
for (int i = 0; i < n; i++)
{
//plaintext = Hello (H - 65 = 7 (8TH INDEX) IN OUR KEY)
if (isalpha(plaintext[i]))
{
if (isupper(plaintext[i]))
{
int j = plaintext[i] - 'A';
printf("%c", toupper(key[j]));
}
if (islower(plaintext[i]))
{
int q = plaintext[i] - 'a';
printf("%c", tolower(key[q]));
}
}
else if (isdigit(plaintext[i]))
{
printf("%c", plaintext[i]);
}
else
{
printf("%c", plaintext[i]);
}
}
printf("\n");
}

check50 tells you what argument it uses for the test. When you run your code with that argument, does it complain about duplicate characters in the key?
This program will not find a duplicate if the second occurance of a character is in upper case.

Related

How to handle handles lack of argv[1] and handles too many arguments in caesar?

I finished Caesar pset2 for CS50, but when I run it for a check-up, I get 2 errors. One for how handles lack of argv[1] and the other being too many arguments. I've been stuck on this for several hours and haven't made any progress. Any tips on how to move forward?
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
int strtoint;
int onlydigits = 0;
if (argc == 2) //Checks the program with one command-line argument
{
for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
if (isdigit(argv[1][i]))
{
onlydigits += 1;
}
}
if (onlydigits == strlen(argv[1])) //Checks if characters are digits
{
strtoint = atoi(argv[1]); //Converts string to int
string plain = get_string("plaintext: "); //Prompt user for input
printf("ciphertext: ");
for (int j = 0, m = strlen(plain); j < m; j++) //Iterate over each character for plaintext
{
if (isalpha(plain[j]) && isupper(plain[j])) //Checks if characters are uppercase
{
printf("%c", (((plain[j] - 65) + strtoint) % 26) + 65);
}
else if (isalpha(plain[j]) && islower(plain[j])) //Checks if characters are lowercase
{
printf("%c", (((plain[j] - 97) + strtoint) % 26) + 97);
}
else
{
printf("%c", plain[j]); //Prints as is if neither of the above
}
}
printf("\n"); //Prints a new line
return 0;
}
else
{
printf("Usage: ./caesar key\n");
return 1;
}
}
}
output for code

CS50: check50 says Substitution problem output is empty, but it works fine on the terminal

I tried to do the substitution problem in CS50's Week 2 Problem Set (essentially, we use an encryption key provided by the user to substitute values, preserving the original message case).
When I test the code myself, it prints all the characters correctly, but check50 says there is no output. See my test results in detail here.
:( encrypts "A" as "Z" using ZYXWVUTSRQPONMLKJIHGFEDCBA as key
expected "ciphertext: Z...", not ""
My code handles all the edge cases perfectly, but check50 says the substitution gives empty outputs ... but it works fine on my online terminal.
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
string substitution(string text, string key);
int main(int argc, string argv[])
{
// making sure there's exactly two arguments
if (argc != 2)
{
printf("Usage: ./substitution key\n");
return 1;
// making sure the key has 26 characters
} else if (strlen(argv[1]) != 26)
{
printf("Key must contain 26 characters.\n");
return 1;
}
// making sure there is no repeating characters in key
for (int i = 0; i < strlen(argv[1]); i++)
{
for (int j = 0; j < strlen(argv[1]); j++)
{
if (argv[i] == argv[j] && i != j)
{
printf("No repeating characters.\n");
return 1;
}
}
}
// if the key is valid...
printf("plaintext: ");
string text = get_string("Type a string: ");
string key = argv[1];
int l = strlen(text);
char ciphertext[l + 1];
// converts the whole key to uppercase
for (int k = 0; k < strlen(key); k++)
{
key[k] = toupper(key[k]);
}
string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// loops through all the characters in text
int length = strlen(text);
for (int i = 0; i < length; i++)
{
for (int j = 0; j < 26; j++)
{
if (isalpha(text[i]) && toupper(text[i]) == alphabet[j] && isupper(text[i]))
{
// printf("%c", key[j]);
ciphertext[i] = key[j];
break;
} else if (isalpha(text[i]) && toupper(text[i]) == alphabet[j] && islower(text[i]))
{
ciphertext[i] = tolower(key[j]);
// printf("%c", tolower(key[j]));
break;
} else
{
ciphertext[i] = text[i];
// printf("%c", text[i]);
}
}
}
// Add null char to make it a string
ciphertext[l] = '\0';
printf("ciphertext: %s\n", ciphertext);
return 0;
}
PS: My problem is similar to this question, but there was no solution provided. The code was excluded due to "academic honest policy", but I'm doing this merely because I'm genuinely stuck and I don't want to copy someone's solution.
Edit. 1: I included a piece of the code for brevity, but I was asked for the entire code. I'm working on the improvements you guys suggested.
by the way you can simply do this to encrypt you don't need all that extra stuff
for (int i = 0; i < strlen(plaintext); i++)
{
if (islower(plaintext[i]))
{
plaintext[i] = tolower(argv[plaintext[i] - 97]);
}
else if (isupper(plaintext[i]))
{
plaintext[i] = toupper(argv[plaintext[i] - 65]);
}
}

CS50/Substitution – Why does the tolower() function not work in my code?

Can someone explain if I switch
// 3.3 Must not contained repeated letters |
if (toupper(argv[1][j] == toupper(argv[1][k])))
to
if (tolower(argv[1][j] == tolower(argv[1][k])))
why it doesn't work anymore, even though the letters could be the same the computer doesn't recognize it?
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc,string argv[])
{
int count_key_char = 0;
int count_repeated_char = 0;
//Exactly 1 command line argument
if (argc == 2)
{
//Must all be letters
for (int i = 0; i < strlen(argv[1]); i++)
{
if (isalpha(argv[1][i]))
{
count_key_char++;
}
}
// 3.3 Must not contained repeated character/s
for (int j = 0, n = strlen(argv[1]); j < n; j++)
{
for (int k = j + 1; k < n; k++)
{
if (toupper(argv[1][j] == toupper(argv[1][k])))
{
count_repeated_char++;
}
}
}
// Must be 26 characters (Fail criteria)
if (strlen(argv[1]) != 26)
{
printf("Key must contain 26 characters.\n");
return 1;
}
// Must be all letters (Fail criteria)
else if (count_key_char != strlen(argv[1]))
{
printf("Key must only contain alphabetic characters.\n");
return 1;
}
// Must not contained repeated character/s (Fail criteria)
else if (count_repeated_char != 0)
{
printf("Key must not contain repeated characters.\n");
return 1;
}
// 4. Get plaintext; Prompt user for plaintext
else
{
string plaintext = get_string("Plaintext: ");
printf("ciphertext: ");
for (int w = 0; w < strlen(plaintext); w++)
{
// If character are letter & uppercase
if (isalpha(plaintext[w]) && isupper(plaintext[w]))
{
int upper = (plaintext[w] -65);
printf("%c", toupper(argv[1][upper]));
}
// If character are lower & lowercase
else if (isalpha(plaintext[w]) && islower(plaintext[w]))
{
int lower = (plaintext[w] - 97);
printf("%c", tolower(argv[1][lower]));
}
// If character are not letter, print as it is
else
{
printf("%c", plaintext[w]);
}
}
printf("\n");
return 0;
}
}
else
{
printf("Usage: ./substitution key\n");
return 1;
}
}
There is a misplaced close paren ) in this line
if (toupper(argv[1][j] == toupper(argv[1][k])))
The toupper will fail if the letters are lower case; the tolower will fail if the letters are upper case.
It is evaluating this
argv[1][j] == toupper(argv[1][k])
which will return 1 (true) if both characters are the same upper case letter. If the key is entered in lower case line will return 0 (false) and program will not consider it a repeated character.
Properly enclose the toupper argument in parentheses and the problem will be solved.

Pset 2 CS50 Substitution Problem, If statement assigns variables(i guess)

I created a code for pset2 problem, named substitution in C.
The programs takes an String of Characters in command-line and apply it to a given text and changes it, printing the ciphertext.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{
//First part, checks KEY input
if (argc != 2) // checks quantity of command-line arguments
{
printf("Usage: ./substitution KEY\n");
return 1;
}
int i = 0;
int largo = strlen(argv[1]);
while (i < largo) //checks if char are alphabetic
{
if (isalpha(argv[1][i]) == 0)
{
printf("Key must contain only alphabetic characters\n");
return 1;
}
else //changes to uppercase
{
argv[1][i] = toupper(argv[1][i]);
}
i++;
}
if (i != 26) //checks length of Key
{
printf("Key must be 26 characters long\n");
return 1;
}
for (int j = 0; j < largo - 1; ++j) //checks repetition of characters
{
for (int k = j + 1; k < largo; ++k)
{
if (argv[1][j] == argv[1][k])
{
printf("Key must not have duplicated characters\n");
return 1;
}
}
}
//second part asks for input
//declaration of strings to get and transform
string plaintext = get_string("plaintext:");
string alfabeto = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string ciphertext = plaintext;
//third part: cifrado
for (int x = 0; x < strlen(plaintext); ++x)
{
if (isalpha(plaintext[x]) != 0)
{
int lower = 0;
if (islower(plaintext[x]) != 0) // is lower case?
{
lower = 1;
plaintext[x] = toupper(plaintext[x]);
}
for (int y = 0; y < strlen(alfabeto); ++y)
{
//printf("alfa: %c text: %c\n", alfabeto[y], plaintext[x]);
if (alfabeto[y] == plaintext[x])
{
ciphertext[x] = argv[1][y];
//printf("c: %s\n", ciphertext);
break;
}
}
if (lower == 1)
{
ciphertext[x] = tolower(ciphertext[x]);
}
}
}
printf("ciphertext: %s", ciphertext);
printf("\n");
return 0;
}
The issue is that the last if statement, kind of assigns the character in "ciphertext" to the "plaintext" variable, so i had to put a break statement in it, to stop that.
Any guesses why this program doesn't work as intended when there's no "break" statement?
if (alfabeto[y] == plaintext[x])
{
ciphertext[x] = argv[1][y];
//printf("c: %s\n", ciphertext);
break;
}

CS50 Substitution - Does not output ciphertext - logic error

The function of the program is to be run with a command-line argument, for example, might be the string NQXPOMAFTRHLZGECYJIUWSKDVB. This 26-character key means that A (the first letter of the alphabet) should be converted into N (the first character of the key), B (the second letter of the alphabet) should be converted into Q (the second character of the key), and so forth. A message like HELLO, then, would be encrypted as FOLLE, replacing each of the letters according to the mapping determined by the key.
e.g.
./substitution JTREKYAVOGDXPSNCUIZLFBMWHQ
plaintext: HELLO
ciphertext: VKXXN*
After starting the program with a valid command-line argument, the program doesn't output anything. It should output the ciphertext which has been encrypted using the key. I can't seem to find where the logic error is.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
bool is_valid_key(string plaintext);
int main(int argc, string argv[])
{
//Error message if user inputs incorret comand-line argument
if (argc != 2)
{
printf("Usage: ./substitution key\n");
return 1;
}
if (!is_valid_key(argv[1]))
{
printf("Key must contain 26 characters.\n");
return 1;
}
//Prompts user for plaintext
string plaintext = get_string("Plaintext: ");
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(plaintext); i < len; i++)
{
if(isalpha(plaintext[i]))
{
plaintext[i] = plaintext[i] + difference[plaintext[i] - (isupper(plaintext[i]) ? 'A' : 'a')];
}
printf("%c", plaintext[i]);
}
printf("\n");
}
//Checks vailidity of the key
bool is_valid_key(string plaintext)
{
int len = strlen(plaintext);
if (len != 26)
{
return false;
}
int freq[26] = { 0 };
for (int i = 0; i < len; i++)
{
if (!isalpha(plaintext[i]))
{
return false;
}
int index = toupper(plaintext[i]) - 'A';
if (freq[index] > 0)
{
return false;
}
freq[index]++;
}
return true;
}
Line 25 should have been for (int i = 'A'; i <= 'Z'; i++).
Line 29 should have been printf("ciphertext: ");

Resources