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

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;
}

Related

Why my ciphered text string is longer than expected?

I'm facing the CS50's substitution problem.
It works, even though the code is not very optimized.
The problem is that i had to add this line of code at the end to make it work:
`
cipher_text[strlen(plain_text)] = '\0';
`
otherwise the lenght of the cipher_text is longer than expected.
Can you tell me why?
this is the code i've written.
`
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(int argc, string argv[])
{
// check if there's 1 argument, if there are > 1 or < 0 print error message and return 1
if (argc != 2)
{
printf("Error, type 1 command\n");
return 1;
}
string key = argv[1];
long lenght = strlen(key);
// check if the key is valid (26 characters) or not, if not return 1 and print error
if (lenght != 26)
{
printf("Key must contain 26 characters.\n");
return 1;
}
// iterate throughout the key, element after element whith the 1st for loop
//check if contains letters or something else in the 1st if
//make the key all lower in order to compare letter repetition in the else if
//check for double letters (compare every letter (key[i]) with all the other letters) in the second for loop
for (int i = 0 ; i < lenght ; i++)
{
if (isalpha(key[i]) == 0) //(key[i] < 65 || key[i] > 90) && (key[i] < 97 || key[i] > 122))
{
printf("Key must contain only letters\n");
return 1;
}
else if (isupper(key[i]))
{
key[i] = tolower(key[i]);
}
for (int j = 0 ; j < lenght ; j++)
{
if (j != i && key[j] == key[i])
{
printf("You can't repeat letters in key (you've repeated the letter %c)\n", key[j]);
return 1;
}
}
}
//ask user for the text to cipher
string plain_text = get_string("plaintext: ");
char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
char ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char cipher_text[strlen(plain_text)];
// iterate through every index in plain_text
//if it is not alphabetical, add it to cipher text
//otherwise, check if it is lower or upper, and add to cipher_text
//
for (int j = 0; j < strlen(plain_text) ; j++)
{
if (isalpha(plain_text[j]) == 0)
{
cipher_text[j] = plain_text[j];
}
for (int x = 0 ; x < lenght ; x++)
{
if(islower(plain_text[j]))
{
if (plain_text[j] == alphabet[x])
{
cipher_text[j] = key[x];
}
}
else if (isupper(plain_text[j]))
{
if (plain_text[j] == ALPHABET[x])
{
cipher_text[j] = toupper(key[x]);
}
}
}
}
cipher_text[strlen(plain_text)] = '\0';
printf("ciphertext: %s\n", cipher_text);
return 0;
}
`

substitution cs50 - handle repeating characters in key

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.

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.

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: ");

Program not encrypting properly with spaces

I have tried to create an implementation of a vigenere cipher, but have come across a hurde in the form of the program not working properly when given spaces in the input. (Assume keyword bacon)
With Spaces
Input
Meet me
Correct Output
Negh zf
Actual Output
Negh Ne
Without Spaces
Input
Meetme
Ouput
Neghzf
So clearly the program is working for strings without the spaces. Anywhere here is the code and thanks in advance for help.
#include <string.h>
#include <stdio.h>
#include <ctype.h>
char encrypt(int key, char a);
int hash(char a);
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("You need a keyword!");
return 1;
}
string keyword = argv[1];
for (int j = 0; j != strlen(keyword); ++j)
{
if (!isalpha(keyword[j]))
{
printf ("The keyword needs to be all words!");
return 1;
}
}
string text = GetString();
for (int i = 0, j = 0; i != strlen(text); ++i, ++j)
{
if (j == strlen(keyword))
{
j = 0;
}
int key = 0;
if (isupper(keyword[j]))
{
key = keyword[j] - 'A';
text[i] = encrypt(key, text[i]);
}
else if (islower(keyword[j]))
{
key = keyword[j] - 'a';
text[i] = encrypt(key, text[i]);
}
else if (isspace(text[i]))
{
j = j - 1;
}
}
printf ("%s\n", text);
}
char encrypt(int key, char a)
{
if (isalpha(a))
{
int total = (int) a + key;
if (isupper(a))
{
while (total > 90)
{
total = total - 26;
}
}
else if (islower(a))
{
while (total > 122)
{
total = total - 26;
}
}
return (char) total;
}
else
{
return a;
}
}
the problem is inside your for loop. Try to correct it in the following way (you will understand easily the mistake):
for (int i = 0, j = 0; i != strlen(text); ++i, ++j)
{
if (j == strlen(keyword))
{
j = 0;
}
// the following check mmust be done here
if (isspace(text[i])) {
j = j - 1;
}
int key = 0;
if (isupper(keyword[j]))
{
key = keyword[j] - 'A';
text[i] = encrypt(key, text[i]);
}
else if (islower(keyword[j]))
{
key = keyword[j] - 'a';
text[i] = encrypt(key, text[i]);
}
}
It looks like you are reading your words from command line arguments; however, command line arguments are typically separated by whitespace. Your program doesn't know that those spaces are supposed to be part of the input.
You need to change the way you are reading input.

Resources