1

I'm trying to invert the case manually, and I tried this:

char* invertirCase(char* str){
    int size = 0;
    char* iterador = str;
    char* retorno = str;

    while (*iterador != '\0') {

        if (retorno[size] < 96) {
            retorno[size] = *iterador + 32;
        }
        else {
            retorno[size] = *iterador - 32;
        }
        iterador++;
        size++;
    }

    return retorno;
}

I'm trying to figure out where's the error, but I don't get it since I'm pretty new at C++ language.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
tonga
  • 191
  • 3
  • 12
  • 4
    Please choose one language. Are you using C or C++? – Yksisarvinen Mar 21 '22 at 20:41
  • 6
    Perhaps the error is coming from where you call the function, not from within the function. E.g. if you went `invertirCase("Lol")` – M.M Mar 21 '22 at 20:42
  • Isn't it the same since I'm not using OOP? It's C++ – tonga Mar 21 '22 at 20:42
  • 2
    Where in the code do you convert a string constant to `char *`? Do we need to see the code that calls `invertircase`? – M Oehm Mar 21 '22 at 20:43
  • 4
    C and C++ handle this somewhat differently. C admits that most of the time doing what you got an error message for is a dumb thing to do, but they let you do it anyway. C++ Stops the build dead and demands you fix it. – user4581301 Mar 21 '22 at 20:43
  • 3
    *Isn't it the same since I'm not using OOP?* No, modern C++ and modern C have diverged a long time ago. C++ is not, and has never been (as the list of discrepancies continues to grow as each language continues to evolve), a proper superset of C. – Eljay Mar 21 '22 at 20:45
  • 3
    @DiegoGómez C and C++ have a common subset, but they are not the same (and if the commenters are right, your code could've compiled in C, but not in C++). And you can write OOP in C as well, just the language doesn't provide much support for that. OOP is a mindset, not the word `class`. – Yksisarvinen Mar 21 '22 at 20:45
  • 1
    This doesn't address the question, but you might want to look at [`std::isupper`](https://en.cppreference.com/w/cpp/string/byte/isupper), [`std::islower`](https://en.cppreference.com/w/cpp/string/byte/islower), [`std::toupper`](https://en.cppreference.com/w/cpp/string/byte/toupper), and [`std::tolower`](https://en.cppreference.com/w/cpp/string/byte/tolower) rather than hand-rolling non-portable versions of these functions. – Pete Becker Mar 21 '22 at 20:47
  • Unrelated: Consider replacing the 96 and 32 with the proper characters. It'll make the code a lot easier to process for the folks who haven't memorized the ascii table. Plus, not everyone uses ascii. And watch out for digits. – user4581301 Mar 21 '22 at 20:48

2 Answers2

2

Why do I get "forbids converting a string constant to ‘char*’" in C++?

The error message means that you are trying to pass a string literal to the function.

String literals in C++ have types of constant character arrays that passed by value to functions are implicitly converted to the type const char *. And any attempt to change a string literal results in undefined behavior.

You could pass to the function a character array initialized by a string literal as for example

char s[] = "Hello";
std::cout << invertirCase( s ) << '\n';

In turn the function can be defined the following way

#include <cctype>

char * invertirCase( char *str )
{
    for ( char *p = str; *p; ++p )
    {
        unsigned char c = *p;

        if ( std::isalpha( c ) )
        {
            if ( std::islower( c ) )
            {
                *p = std::toupper( c );
            }
            else
            {
                *p = std::tolower( c );
            }
        }
    }

    return str;
}

or

char * invertirCase( char *str )
{
    for ( char *p = str; *p; ++p )
    {
        unsigned char c = *p;

        if ( std::islower( c ) )
        {
            *p = std::toupper( c );
        }
        else if ( std::isupper( c ) )
        {
            *p = std::tolower( c );
        }
    }

    return str;
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

There is no "string constant" in the code you have shown, so it would have to be at the call site, ie if you were doing something like invertirCase("string"), which will not work, for 2 reasons:

  1. since C++11 onward, C++ does not allow a string literal to be assigned to a char* pointer. This is because a string literal is a const char[] array, and you can't have a pointer-to-non-const pointing at const data. So you need to use const char* instead.

  2. however, that will still not work, because invertirCase() modifies the data pointed at by its str parameter. You can't modify the data of a string literal.

So, you will have to make a copy of the string literal into writable memory. You can either make that copy at the call site, eg:

char str[] = "string";
invertirCase(str);

Or, you can make the copy inside of invertirCase() (but then the caller will have to free the copy when done using it), eg:

char* invertirCase(const char* str){
    int size = 0;
    char* retorno = new char[strlen(str)+1];

    while (*str != '\0') {
        retorno[size] = (*str < 96) ? (*str + 32) : (*str - 32);
        str++;
        size++;
    }

    retorno[size] = '\0';

    return retorno;
}
char *str = invertirCase("string");
...
delete[] str;

Otherwise, simply don't use char* at all. Use std::string instead, eg:

std::string invertirCase(const std::string &str){
    std::string retorno;
    retorno.reserve(str.size());
    for(char ch : str) {
        retorno.push_back((ch < 96) ? (ch + 32) : (ch - 32));
    }
    return retorno;
}
std::string str = invertirCase("string");
...
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770