Why am I getting same characters with any key I type? - cs50

Why am I getting this return 4 repeated characters for Pset2 Substition CS50
Everything seems to work fine except for the checking for repeated characters in the command line argument. Rest of the code works fine when I remove this return for the checking repeated characters. Everything I type gives me this error
#include <cs50.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
int main(int argc, string argv[])
{
if (argc == 2)
{
//When there are 26 characters in string
if (strlen(argv[1]) == 26)
{
string check = argv[1];
//Checking each characters in string(array) where [i] is the array number
for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
//If the characters in the string is alphabet or not
if (!isalpha(argv[1][i]))
{
printf("Key must only contain Alphabetic Characters\n");
return 3;
}
//Check for repeated alphabet
for (int l = 0; l < n; l++)
{
if (argv[1][i] == check[l])
{
printf("Key must not contain repeated Characters\n");
return 4;
}
}
}
//Get Plaintext
string plaintext = get_string("Plaintext: ");
//Going through each characters in string
for (int j = 0, n = strlen(plaintext); j < n; j++)
{
//For LOWERCASE CHARACGERS
if (plaintext[j] >= 'a' && plaintext[j] <= 'z')
{
plaintext[j] = argv[1][plaintext[j] - 97];
plaintext[j] = tolower(plaintext[j]);
}
//For UPPERCASE CHARACTERS
else if (plaintext[j] >= 'A' && plaintext[j] <= 'Z')
{
plaintext[j] = argv[1][plaintext[j] - 65];
plaintext[j] = toupper(plaintext[j]);
}
}
printf("Ciphertext: %s\n",plaintext);
}
//If Characters are not 26 in string
else
{
printf("Key must contain 26 Characters\n");
return 2;
}
}
//When Location is other than argv[1]
else
{
printf("./substitution KEY\n");
return 1;
}
}

When i is 0 and l is 0 what is being compared here if (argv[1][i] == check[l])? Actually whenever i and l are equal it is comparing a character to itself. Program does not need to compare any characters it has already processed. The compare should start at the current char + 1.

Related

cs50x 2020 - pset2 - substitution - duplicate characters in key

I keep getting an error around handling duplicate characters in key when checking my code for the substitution problem within pset2 of the cs50 course 2020. My code and further details are below - can anyone please help with this? Thanks
The error message it gives me is
:( handles duplicate characters in key
timed out while waiting for program to exit
When I check my code for duplicate characters it seems to work fine (printing Usage: ./substitution key and ending the program)
Code below
# include <stdio.h>
# include <cs50.h>
# include <string.h>
# include <stdlib.h>
# include <ctype.h>
int main(int argc, string argv[])
{
// Check that only one argument submitted
if (argc == 2)
{
// Check that key contains 26 characters
int keylen = strlen(argv[1]);
if (keylen == 26)
{
// Check that all characters are letters
for (int i = 0; i < keylen; i++)
{
bool lettercheck = isalpha(argv[1][i]);
if (lettercheck == true)
{
// THIS IS CAUSING ERROR - Check that no letters have been repeated - put all in lowercase to do so
for (int n = 0; n < i; n++)
{
char currentletter = argv[1][i];
char previousletter = argv[1][i - 1];
if (tolower(currentletter) == tolower(previousletter))
{
printf("Usage: ./substitution key\n");
return 1;
}
}
}
else
{
printf("Usage: ./substitution key\n");
return 1;
}
}
}
else
{
printf("Key must contain 26 characters.\n");
return 1;
}
}
else
{
printf("Usage: ./substitution key\n");
return 1;
}
// Get user input
string input = get_string("plaintext: ");
//Transform input using key
for(int i = 0; i < strlen(input); i++)
{
char currentletter = input[i];
int testlower = islower(currentletter);
int testupper = isupper(currentletter);
if (testupper > 0)
{
int j = input[i] - 65;
input[i] = toupper(argv[1][j]);
}
else if (testlower > 0)
{
int j = input[i] - 97;
input[i] = tolower(argv[1][j]);
}
}
printf("ciphertext: %s\n", input);
}
Edit:
Figured out solution - problem was with the second for loop was iterating against i - 1 times instead of n times
Code should have been
charpreviouslletter = argv[1][n]
instead of
charpreviousletter = argv[1][i - 1]
for (int n = 0; n < i; n++)
{
char currentletter = argv[1][i];
char previousletter = argv[1]**[i - 1]**
In this loop-
// THIS IS CAUSING ERROR - Check that no letters have been repeated - put all in lowercase to do so
for (int n = 0; n < i; n++)
{
char currentletter = argv[1][i];
char previousletter = argv[1][i - 1];
if (tolower(currentletter) == tolower(previousletter))
{
printf("Usage: ./substitution key\n");
return 1;
}
}
you're comparing only the current character to the previous character. This doesn't work for strings like abcdefca
Notice how, c and a have duplicates - but they're not right next to their originals and hence your logic won't find these duplicates. Your logic will only work for duplicates that are next to each other such as aabcddef.
Instead, you need to take a note of which characters you've encountered whilst looping through. If you encounter a character that you have already encountered, you know there's a duplicate.
Thankfully, the key is only expected to contain all 26 characters of the alphabet without any duplicates. This means you can simply have an int array of 26 slots - each slot counts the number of appearances of the letter at that index. 0th index stands for 'a', 1st for 'b' and so on.
This way, you can very easily get the index of an alphabetic character using letter - 'a', where letter is the alphabetic character. So if the letter was a, you'd get 0, which is indeed the index of 'a'
Also, you have a nested loop while traversing the key, this nested loop also traverses through the key. Except it does it only up until a certain index, the index being the current index of the outer loop. This seems wasteful and weird. Why not simply loop through once, check if current character is an alphabetic letter and also check if this letter has been encountered before. That's all you have to do!
int letter_presence[26];
char upperletter;
string key = argv[1];
if (strlen(key) == KEY_LEN)
{
for (int index = 0; index < KEY_LEN; index++)
{
if (!isalpha(key[index]))
{
// Wrong key - invalid character
printf("Usage: ./substitution key\n");
return 1;
}
if (letter_presence[tolower(key[index]) - 'a'] == 0)
{
// This letter has not been encountered before
letter_presence[upperletter - 'A'] = 1;
}
else
{
// Wrong key - Duplicate letters
return 1;
}
}
// All good
}

Caesar problem code generating "error: implicitly declaring library function 'strlen' with type 'unsigned long (const char *)'

I am doing the CS50 course and am on week 2. One of the problems of week 2 is called "Caesar". Essentially you have to write code which cyphers text by shifting letters that use the users inputted preferred number. After running my code I keep getting this error
"error: implicitly declaring library function 'strlen' with
type 'unsigned long (const char *)'
[-Werror,-Wimplicit-function-declaration]
for(i = 0, l = strlen(text); i < n; i++)"
This is the code:
int main(int argc, string argv[])
{
string n = argv[1];
int y = argc;
int key = get_int("./caesar ");//getting the number from the user
int k = (key);//assigning key a variable name.
string text = get_string("plaintext: ");//letting the user input their text.
if (key < 1)//Trying to make limit for acceptable input.
{
printf("ERROR");
return 1;
}
int l;
int i;
//for loop containing the encipher process
for(i = 0, l = strlen(text); i < n; i++)
{
if(isalpha(i))
{
if (isupper[i])
{
printf("ciphertext: %c",(text[i] + k)%26 + 65);
}
else (islower[i])
{
printf("ciphertext: %c",(text[i] + k)%26 + 65);
}
}
}
printf("ciphertext: %c", d || c);
return;
int checking_key(int y,string n)
int num = argc;
string key = y;
int num_key = atoi(key);
if(argc != 2)
{
return 0;
}
else
{
if (num_key > 0)
{
return num_key;
}
else
{
return 0;
}
}
}
From man strlen:
Synopsis
#include <string.h>
size_t strlen(const char *s);
Just like one needs to "include" cs50.h to use any of the get_* functions, string.h must be "include"d to access its functions, eg strlen.
Additionally (per comments):
The "ordered comparison" in the compile error
ordered comparison between pointer and integer ('int' and 'string' (aka 'char *')) [-Werror] for(i = 0, l = strlen(text); i < n; i++)
is i < n. Error says one of them is an int and one of them is a string.
On closer inspection this program is a long way from a clean compile. Recommend you follow along with the spec and "approach this problem one step at a time"

getting the last 9 digits of a char buffer in Arduino

In a previous code of mine, I was using the following line of code to get the last 9digits of the "command" string
if(command.indexOf("kitchen light: set top color") >=0)
{OnColorValueRed = (command.charAt(28)- 48)*100 + (command.charAt(29)- 48)*10 + (command.charAt(30)- 48);}
Now i am using a char buffer (char packetBuffer[UDP_TX_PACKET_MAX_SIZE];) and using the above code does not work since packetBuffer is not a string, how could I please go about this
Try defining a function to search the string
int indexOf_for_char(const char *str, int str_length, const char *target) {
// naive method
for (int index = 0; index < str_length; index++) {
int j;
// check if matched
for (j = 0; target[j] != '\0' && index + j < str_length && str[index + j] == target[j]; j++);
// if matched, return the index
if (target[j] == '\0') return index;
}
return -1;
}
and using subscripting.
if(indexOf_for_char(packetBuffer, UDP_TX_PACKET_MAX_SIZE, "kitchen light: set top color") >=0)
{OnColorValueRed = (packetBuffer[28]- 48)*100 + (packetBuffer[29]- 48)*10 + (packetBuffer[30]- 48);}

Vigenere.c CS50 Floating Point Exception (Core Dumped)

I am working on the Vigenere exercise from Harvard's CS50 (in case you noticed I'm using string and not str).
My program gives me a Floating Point Exception error when I use "a" in the keyword.
It actually gives me that error
when I use "a" by itself, and
when I use "a" within a bigger word it just gives me wrong output.
For any other kind of keyword, the program works perfectly fine.
I've run a million tests. Why is it doing this? I can't see where I'm dividing or % by 0. The length of the keyword is always at least 1. It is probably going to be some super simple mistake, but I've been at this for about 10 hours and I can barely remember my name.
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main (int argc, string argv[])
{
//Error message if argc is not 2 and argv[1] is not alphabetical
if (argc != 2)
{
printf("Insert './vigenere' followed by an all alphabetical key\n");
return 1;
}
else if (argv[1])
{
for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
if (isalpha((argv[1])[i]) == false)
{
printf("Insert './vigenere' followed by an all alphabetical key\n");
return 1;
}
}
//Store keyword in variable
string keyword = argv[1];
//Convert all capital chars in keyword to lowercase values, then converts them to alphabetical corresponding number
for (int i = 0, n = strlen(keyword); i < n; i++)
{
if (isupper(keyword[i])) {
keyword[i] += 32;
}
keyword[i] -= 97;
}
//Ask for users message
string message = GetString();
int counter = 0;
int keywordLength = strlen(keyword);
//Iterate through each of the message's chars
for (int i = 0, n = strlen(message); i < n; i++)
{
//Check if ith char is a letter
if (isalpha(message[i])) {
int index = counter % keywordLength;
if (isupper(message[i])) {
char letter = (((message[i] - 65) + (keyword[index])) % 26) + 65;
printf("%c", letter);
counter++;
} else if (islower(message[i])) {
char letter = (((message[i] - 97) + (keyword[index])) % 26) + 97;
printf("%c", letter);
counter++;
}
} else {
//Prints non alphabetic characters
printf("%c", message[i]);
}
}
printf("\n");
return 0;
}
}
This behavior is caused by the line keyword[i] -= 97;, there you make every 'a' in the key stream a zero. Later you use strlen() on the transformed key. So when the key starts with an 'a', keywordLength therefor is set to zero, and the modulo keywordLength operation get into a division by zero. You can fix this by calculating the keyword length before the key transformation.

Sub sequence occurrence in a string

Given 2 strings like bangalore and blr, return whether one appears as a subsequence of the other. The above case returns true whereas bangalore and brl returns false.
Greedy strategy should work for this problem.
Find the first letter of the suspected substring (blr) in the big string (*b*angalore)
Find the second letter starting at the index of the first letter plus one (anga*l*ore)
Find the third letter starting at the index of the second letter plus one (o*r*e)
Continue until you can no longer find the next letter of blr in the string (no match), or you run out of letters in the subsequence (you have a match).
Here is a sample code in C++:
#include <iostream>
#include <string>
using namespace std;
int main() {
string txt = "quick brown fox jumps over the lazy dog";
string s = "brownfoxzdog";
int pos = -1;
bool ok = true;
for (int i = 0 ; ok && i != s.size() ; i++) {
ok = (pos = txt.find(s[i], pos+1)) != string::npos;
}
cerr << (ok ? "Found" : "Not found") << endl;
return 0;
}
// Solution 1
public static boolean isSubSequence(String str1, String str2) {
int i = 0;
int j = 0;
while (i < str1.length() && j < str2.length()) {
if (str1.charAt(i) == str2.charAt(j)) {
i++;
j++;
} else {
i++;
}
}
return j == str2.length();
}
// Solution 2 using String indexOf method
public static boolean isSubSequenceUsingIndexOf(String mainStr, String subStr) {
int i = 0;
int index = 0;
while(i<subStr.length()) {
char c = subStr.charAt(i);
if((index = mainStr.indexOf(c, index)) == -1) {
return false;
}
i++;
}
return true;
}
O(N) solution, where N is the length of the substring.
bool subsequence( string s1, string s2 ){
int n1 = s1.length();
int n2 = s2.length();
if( n1 > n2 ){
return false;
}
int i = 0;
int j = 0;
while( i < n1 && j < n2 ){
if( s1[i] == s2[j] ){
i++;
}
j++;
}
return i == n1;
}
Find the length of the longest common subsequence. If it is equal to the length of small string, return true

Resources