Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unsure as to why toupper() is cutting off last letter in C

So the goal of this program is to basically take a 26 letter 'key' in the terminal (through argv[]) and use its index's as a substitution guideline. So there are 2 inputs you enter in the terminal, one in the argv[] and one is just a plain get_string() input. The argv[] input will look like this: ./s YTNSHKVEFXRBAUQZCLWDMIPGJO where s is the file name. And then the get_string() input will look like this: plaintext: HELLO. (The input is HELLO). What the program will then do is loop through all the letters in the plaintext input and substitute its alphabetical index according to the index of the argv[] key. For example, H has an alphabetical index of 7 (where a = 0 and z = 25), so we look at the 7th index in the key YTNSHKV(E)FXRBAUQZCLWDMIPGJO which in this case is E. It does this for each letter in the input and we'll end up with the output ciphertext: EHBBQ. This is what it should look like in the terminal:

./s YTNSHKVEFXRBAUQZCLWDMIPGJO
plaintext:  HELLO
ciphertext: EHBBQ

But my output is EHBB, since it cuts off the last letter for some reason when I use toupper().

And also, the uppercase and lowercase depends on the plaintext input, if the plaintext input was hello, world and the argv[] key was YTNSHKVEFXRBAUQZCLWDMIPGJO, the output would be jrssb, ybwsp, and if the input was HellO, world with the same key, the output would be JrssB, ybwsp.

I'm basically done with the problem, my program substitutes the plaintext given into the correct ciphertext based on the key that was inputted through the command line. Right now, say if the plaintext input was HELLO, and the key was vchprzgjntlskfbdqwaxeuymoi (all lowercase), then it should return HELLO and not hello. This is because my program puts all the letters in the command line key into an array of length 26 and I loop through all the plaintext letters and match it's ascii value (minus a certain number to get it into 0-25 index range) with the index in the key. So E has an alphabetical index of 4 so in this case my program would get lowercase p, but I need it to be P, so that's why I'm using toupper().

When I use tolower(), everything worked fine, and once I started using toupper(), the last letter of the ciphertext is cut off for some reason. Here is my output before using toupper():

ciphertext: EHBBQ

And here is my output after I use toupper():

ciphertext: EHBB

Here is my code:

int main(int argc, string argv[]) {
    string plaintext = get_string("plaintext: ");
    
    // Putting all the argv letters into an array called key
    char key[26]; // change 4 to 26
    for (int i = 0; i < 26; i++) // change 4 to 26
    {
        key[i] = argv[1][i];
    }
    
    // Assigning array called ciphertext, the length of the inputted text, to hold cipertext chars
    char ciphertext[strlen(plaintext)];
    
    // Looping through the inputted text, checking for upper and lower case letters
    for (int i = 0; i < strlen(plaintext); i++)
    {
        // The letter is lower case
        if (islower(plaintext[i]) != 0)
        {
            int asciiVal = plaintext[i] - 97; // Converting from ascii to decimal value and getting it into alphabetical index (0-25)
            char l = tolower(key[asciiVal]); // tolower() works properly
            //printf("%c", l);
            strncat(ciphertext, &l, 1); // Using strncat() to append the converted plaintext char to ciphertext
        }
        // The letter is uppercase
        else if (isupper(plaintext[i]) != 0)
        {
            int asciiVal = plaintext[i] - 65; // Converting from ascii to decimal value and getting it into alphabetical index (0-25)
            char u = toupper(key[asciiVal]);  // For some reason having this cuts off the last letter 
            strncat(ciphertext, &u, 1); // Using strncat() to append the converted plaintext char to ciphertext
        }
        // If its a space, comma, apostrophe, etc...
        else
        {
            strncat(ciphertext, &plaintext[i], 1);
        }
    }
    
    // prints out ciphertext output
    printf("ciphertext: ");
    for (int i = 0; i < strlen(plaintext); i++)
    {
        printf("%c", ciphertext[i]);
    }
    printf("\n");
    printf("%c\n", ciphertext[1]);
    printf("%c\n", ciphertext[4]);
    //printf("%s\n", ciphertext);
    return 0;
}
like image 913
Soccerball123 Avatar asked Mar 01 '23 11:03

Soccerball123


1 Answers

The strncat function expects its first argument to be a null terminated string that it appends to. You're calling it with ciphertext while it is uninitialized. This means that you're reading unitialized memory, possibly reading past the end of the array, triggering undefined behavior.

You need to make ciphertext an empty string before you call strncat on it. Also, you need to add 1 to the size of this array to account for the terminating null byte on the completed string to prevent writing off the end of it.

char ciphertext[strlen(plaintext)+1];
ciphertext[0] = 0;
like image 111
dbush Avatar answered Mar 05 '23 17:03

dbush