Quantumpencil Quantumpencil - 4 months ago 10
C Question

CS50 - floating point exception arises when methods are called

I'm a new programmer trying to teach myself by doing the psets for CS50. I wrote the following bit of code, which works without a problem.

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


string vencipher(string text, string key)
{
for (int i=0, j=0, n =strlen(text); i < n; i++,j++)
{
int m = strlen(key);
if (text[i] >= 65 && text[i] <= 90 && key[j % m] >= 65 && key[j % m] <= 90)
{
text[i] = 65 + ((text[i] - 65) + (key[j % m] - 65)) % 26;
}
else if (text[i] >= 65 && text[i] <= 90 && key[j % m] >= 97 && key[j % m] <= 123)
{
text[i] = 65 + ((text[i] - 65) + (key[j % m] - 97)) % 26;
}
else if (text[i] >= 97 && text[i] <= 123 && key[j % m] >= 65 && key[j % m] <= 90)
{
text[i] = 97 + ((text[i] - 97) + (key[j % m] - 65)) % 26;
}
else if (text[i] >= 97 && text[i] <= 123 && key[j % m] >= 97 && key[j % m] <= 123)
{
text[i] = 97 + ((text[i] - 97) + (key[j % m] - 97)) % 26;
}
else
{
text[i] = text[i];
j = j - 1;
}
}
return text;
}

int keyvalidator(string text)
{
int alphalen = 0;
for (int i=0, n=strlen(text); i < n; i++)
{
if ((text[i] >= 97 && text[i] <= 123) || (text[i] >= 65 && text[i] <= 90))
{
alphalen = alphalen + 1;
}
}
if (alphalen == strlen(text))
{
return 1;
}
else
{
return 0;
}
}

int main(int argc, string argv[])
{
if (argc != 2 || keyvalidator(argv[1]) != 1)
{
printf("That is not a valid secret key!\n");
return 1;
}

if (argc == 2)
{
string secretKey = argv[1];
string plainText = GetString();
printf("%s\n", vencipher(plainText, secretKey));
}
return 0;
}


I wanted to try and split up vencipher into some different methods to try and improve the code's readability. This is what I did

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

string keycaseID(string key)
{
for (int i=0, n=strlen(key); i < n; i++)
{
if (key[i] >= 65 && key[i] <= 90)
{
key[i] = 1;
}

else
{
key[i] = 0;
}
}
return key;
}

string setkeycase(string key)
{
for (int i=0, n=strlen(key); i < n; i++)
{
if (keycaseID(key)[i] == 1)
{
key[i] = key [i] - 65;
}
else if (keycaseID(key)[i] == 0)
{
key[i] = key [i] - 97;
}
}
return key;
}

string vencipher(string text, string key)
{
for (int i=0, j=0, n =strlen(text); i < n; i++,j++)
{
int m = strlen(key);
if (text[i] >= 65 && text[i] <= 90 && keycaseID(key)[j % m] == 1)
{
text[i] = 65 + ((text[i] - 65) + setkeycase(key)[j % m]) % 26;
}
else if (text[i] >= 65 && text[i] <= 90 && keycaseID(key)[j % m] == 0)
{
text[i] = 65 + ((text[i] - 65) + setkeycase(key)[j % m]) % 26;
}
else if (text[i] >= 97 && text[i] <= 123 && keycaseID(key)[j % m] == 1)
{
text[i] = 97 + ((text[i] - 97) + setkeycase(key)[j % m]) % 26;
}
else if (text[i] >= 97 && text[i] <= 123 && keycaseID(key)[j % m] == 0)
{
text[i] = 97 + ((text[i] - 97) + setkeycase(key)[j % m]) % 26;
}
else
{
text[i] = text[i];
j = j - 1;
}
}
return text;
}

int keyvalidator(string text)
{
int alphalen = 0;
for (int i=0, n=strlen(text); i < n; i++)
{
if ((text[i] >= 97 && text[i] <= 123) || (text[i] >= 65 && text[i] <= 90))
{
alphalen = alphalen + 1;
}
}
if (alphalen == strlen(text))
{
return 1;
}
else
{
return 0;
}
}

int main(int argc, string argv[])
{
if (argc != 2 || keyvalidator(argv[1]) != 1)
{
printf("That is not a valid secret key!\n");
return 1;
}

if (argc == 2)
{
string secretKey = argv[1];
string plainText = GetString();
printf("%s\n", vencipher(plainText, secretKey));
}
return 0;
}


The newer code compiles but when I run it I get a "floating point exception," which according to my research is the result of modulo divison by 0. I searched my code several times, and I can't find any instance of division by 0. I was wondering if someone could help me find my error and explain to me what's causing the floating point exception here.

Answer

I've also seen floating point exceptions on memory corruptions so that's the more likely scenario given there's not a / character anywhere in your code.

I will tell you something that you're doing wrong. By calling keycaseID() on the same string more than once (as you do in setkeycase(), you're guaranteed to end up with a string of all zeros (0 rather than '0').

The first time it will convert all elements to either 1 or 0 depending on their case (and you therefore lose their original value). The second time, because they're either all 0 or 1, they'll be less than 65 and therefore all set to 0.

Assuming your key is all alpha characters (upper or lower case), you can just use something like this to convert it into values 0 through 25:

for (int i = strlen (key) - 1; i >= 0; i--)  // needs string.h
    if (isupper (key[i]))                    // needs ctype.h
        key[i] -= 'A';
    else
        key[i] -= 'a';

or, even shorter:

for (int i = strlen (key) - 1; i >= 0; i--)  // needs string.h
    key[i] = toupper (key[i]) - 'A';         // needs ctype.h

Neither of those is perfectly portable since C doesn't mandate that A-Z are contiguous code points but, as long as you steer clear of weird non-ASCII environments, you should be fine :-)

Comments