Vigenere.c CS50 Floating Point Exception (Core Dumped) - vigenere

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.

Related

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

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.

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"

Why I cant print initials of a name?

I am trying to write a code that prints initials of a given name? I have been getting error whenever I use '/0' - to initialize the ith character of a given string. I am using it to identify initials of the 2nd word? Any suggestions to detect the 2nd word and print the initial of the 2nd word? Additionally, I am trying to write this code so that it ignores any additional spaces:
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
printf ("Enter you Name:");//print name
string s = get_string(); //get input from user
printf("%c", toupper(s[0])); // use placeholder to call the string
for (int i=0, n = strlen(s); i < n; i++)
{
if (s[i] == '/0')
{
printf("%c", toupper(s[i+1]));
}
}
printf ("\n");
}
I'm not sure what your get_string() function does but this does what you're asking for.
int main(void)
{
printf ("Enter you Name:");//print name
char input[100];
cin.getline(input, sizeof(input));
string s(input);
//get input from user
printf("%c", toupper(s[0])); // use placeholder to call the string
for (int i=0, n = s.length(); i < n; i++)
{
if (isspace(s.at(i)))
{
printf("%c", toupper(s[i+1]));
}
}
printf ("\n");
}
Try to use ' ' instead of '/0'.
if (s[i] == ' ')
or if you prefer ASCII codes (Space is 0x20 or 32 as decimal):
if (s[i] == 0x20)
your code will work if there is only 1 space between names. To avoid this, the condition should also check the next char. If it's not a space then probably it's a 'letter':
if (s[i] == 0x20 && s[i+1] != 0x20) {...
Note that the for cycle should stop at i < n - 1, otherwise the loop will fail if there are trailing spaces...

How to return a int converted to char array back to main for displaying it

My doubts are as follows :
1 : how to send 'str' from function 'fun' , So that i can display it in main function.
2 : And is the return type correct in the code ?
2 : the current code is displaying some different output.
char * fun(int *arr)
{
char *str[5];
int i;
for(i=0;i<5;i++)
{
char c[sizeof(int)] ;
sprintf(c,"%d",arr[i]);
str[i] = malloc(sizeof(c));
strcpy(str[i],c);
}
return str;
}
int main()
{
int arr[] = {2,1,3,4,5},i;
char *str = fun(arr);
for(i=0;i<5;i++)
{
printf("%c",str[i]);
}
return 0;
}
how to send 'str' from function 'fun' , So that i can display it in main function.
This is the way:
char* str = malloc( size );
if( str == NULL ) {
fprintf( stderr,"Failed to malloc\n");
}
/* Do stuff with str, use str[index],
* remember to free it in main*/
free(str);
And is the return type correct in the code ?
No, Probably char** is the one you need to return.
the current code is displaying some different output.
Consider explaining what/why do you want to do ? The way you have written, seems completely messed up way to me. You're passing array of integer but not its length. How is the fun() supposed to know length of array? Another problem is array of pointers in fun().
You can't write a int to a char (See the both size). So I used char array instead.
However, I'm not sure if this is what you want to do (might be a quick and dirty way of doing it):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char**
fun(int *arr, int size)
{
char **str = malloc( sizeof(char*)*size );
if( str == NULL ) {
fprintf( stderr, "Failed malloc\n");
}
int i;
for(i=0;i<5;i++) {
str[i] = malloc(sizeof(int));
if( str == NULL ) {
fprintf( stderr, "Failed malloc\n");
}
sprintf(str[i],"%d",arr[i]);
}
return str;
}
int
main()
{
int arr[] = {2,1,3,4,5},i;
char **str = fun(arr, 5);
for(i=0;i<5;i++) {
printf("%s\n",str[i]);
free(str[i]);
}
free(str);
return 0;
}
I made these changes to your code to get it working:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **fun(int *arr)
{
char **str = malloc(sizeof(char *) * 5);
int i;
for(i = 0; i < 5; i++) {
if ((arr[i] >= 0) && (arr[i] <= 9)) {
char c[2] ;
sprintf(c, "%d", arr[i]);
str[i] = (char *) malloc(strlen(c) + 1);
strcpy(str[i],c);
}
}
return str;
}
int main()
{
int arr[] = {2, 1, 3, 4, 5}, i;
char **str = fun(arr);
for(i = 0; i < 5; i++) {
printf("%s", str[i]);
free(str[i]);
}
printf("\n");
free(str);
return 0;
}
Output
21345
I added a check to make sure that arr[i] is a single digit number. Also, returning a pointer to a stack variable will result in undefined behavior, so I changed the code to allocate an array of strings. I don't check the return value of the malloc calls, which means this program could crash due to a NULL pointer reference.
This solution differs from the others in that it attempts to answer your question based on the intended use.
how to send 'str' from function 'fun' , So that i can display it in main function.
First, you need to define a function that returns a pointer to array.
char (*fun(int arr[]))[]
Allocating variable length strings doesn't buy you anything. The longest string you'll need for 64bit unsigned int is 20 digits. All you need is to allocate an array of 5 elements of 2 characters long each. You may adjust the length to suit your need. This sample assumes 1 digit and 1 null character. Note the allocation is done only once. You may choose to use the length of 21 (20 digits and 1 null).
For readability on which values here are related to the number of digits including the terminator, I'll define a macro that you can modify to suit your needs.
#define NUM_OF_DIGITS 3
You can then use this macro in the whole code.
char (*str)[NUM_OF_DIGITS] = malloc(5 * NUM_OF_DIGITS);
Finally the receiving variable in main() can be declared and assigned the returned array.
char (*str)[NUM_OF_DIGITS] = fun(arr);
Your complete code should look like this:
Code
char (*fun(int arr[]))[]
{
char (*str)[NUM_OF_DIGITS] = malloc(5 * NUM_OF_DIGITS);
int i;
for(i=0;i<5;i++)
{
snprintf(str[i],NUM_OF_DIGITS,"%d",arr[i]); //control and limit to single digit + null
}
return str;
}
int main()
{
int arr[] = {24,1,33,4,5},i;
char (*str)[NUM_OF_DIGITS] = fun(arr);
for(i=0;i<5;i++)
{
printf("%s",str[i]);
}
free(str);
return 0;
}
Output
2413345
With this method you only need to free the allocated memory once.

Resources