Search code examples
c++stringalgorithmuppercaselowercase

I can't find any error that will lead to this result


I am new to C++ and want to test out how much I actually learned so I made this simple cRaZyTeXt generator. But there's a weird bug I can't find any way to solve.

Codes are here:

#include <iostream>
#include <string>
#include <algorithm>
#include <windows.h>

char convertToUppercase (char x)
{
    int asciiCode {static_cast<int>(x) - 32};
    char y {static_cast<char>(asciiCode)};

    return y;
}

char convertToLowercase (char x)
{
    int asciiCode {static_cast<int>(x) + 32};
    char y {static_cast<char>(asciiCode)};

    return y;
}

void toClipboard(const std::string &s){
    OpenClipboard(0);
    EmptyClipboard();
    HGLOBAL hg=GlobalAlloc(GMEM_MOVEABLE,s.size() + 1);
    if (!hg){
        CloseClipboard();
        return;
    }
    memcpy(GlobalLock(hg),s.c_str(),s.size() + 1);
    GlobalUnlock(hg);
    SetClipboardData(CF_TEXT,hg);
    CloseClipboard();
    GlobalFree(hg);
}

int main()
{
    std::cout << "Enter the text you want to convert into cRaZy TeXt: " << '\n';
    std::string userInput {};
    std::getline(std::cin >> std::ws, userInput);

    char userInputArray [userInput.size()];
    std::copy(userInput.begin(), userInput.end(), userInputArray);

    char outputArray [userInput.size()];

    for (int i = 0; i <= userInput.size(); ++i)
    {
        int x {static_cast<int>(userInputArray[i])};
        if (i % 2 == 0)
        {
            if (x <= 90 && x >= 65)
                outputArray[i] = convertToLowercase(userInputArray[i]);
            else
                outputArray[i] = userInputArray[i];
        }
        else
        {
            if (x <= 122 && x >= 97)
                outputArray[i] = convertToUppercase(userInputArray[i]);

            else
                outputArray[i] = userInputArray[i];
        }
    }
    std::cout << outputArray << '\n';
    toClipboard(outputArray);

    system("pause");
    return 0;
}

when I enter Hello, world!, it can output hElLo, WoRlD! as exactly how I want it to be. proof

But when I try my name is sean., its output would look like this: screenshot

mY NaMe iS SeAn.@y name is sean.@%�

What's more weird is that both my name is ma sean. and my name is sean ma. works fine.

my name is ma sean.

my name is sean ma.

I have tried above four inputs in both release and debug configuration and it's all the same.

Please elaborate on the issue and make the explanation friendlier for beginners.

Any helps are appreciated. Thank you in advance.


Solution

  • For starters variable length arrays as for example the declaration of this array

    char userInputArray [userInput.size()];
    

    is not a standard C++ feature.

    There is no need to use auxiliary arrays to perform the task. You could change the original object userInput of the type std::string itself.

    This variable length array

    char outputArray [userInput.size()];
    

    does not contain a space for the terminating zero character '\0' to make the stored sequence of characters a string.

    As a result this output

    std::cout << outputArray << '\n';
    

    invokes undefined behavior.

    This for loop

    for (int i = 0; i <= userInput.size(); ++i)
    

    leads to access memory beyond the declared variable length arrays because the valid range of indices is [ 0, userInput.size() ).

    Also it is a bad idea to use magic numbers like for example 65 or 90. This makes the code unreadable.

    If I have understood correctly what you need is a function like the following shown in the demonstrative program below.

    #include <iostream>
    #include <string>
    #include <cctype>
    
    std::string & cRaZyTeXt_generator( std::string &s )
    {
        int upper_case = 1;
    
        for (auto &c : s)
        {
            if ( std::isalpha( static_cast< unsigned char >( c ) ) )
            {
                if ( ( upper_case ^= 1 ) )
                {
                    c = std::toupper( static_cast< unsigned char >( c ) );
                }
                else
                {
                    c = std::tolower( static_cast< unsigned char >( c ) );
                }
            }
        }
    
        return s;
    }
    
    int main()
    {
        std::string s( "Hello, World!" );
    
        std::cout << s << '\n';
        std::cout << cRaZyTeXt_generator( s ) << '\n';
    }
    

    The program output is

    Hello, World!
    hElLo, WoRlD!