2

Let's say you have:

const char * something = "m";

How would one make this uppercase, using toupper (or something else, if applicable)?

I want to use a char * instead of a string (I can use a string, but then I have to use str.c_str()).

So, how can I make char * something = "m"; contain "M"?

Flare Cat
  • 591
  • 2
  • 12
  • 24
John
  • 107
  • 1
  • 4
  • 11

5 Answers5

8

I find you choice of C strings disturbing.. but anyway.

You can't change a string literal (char *something). Try an array:

char something[] = "m";
something[0] = toupper(something[0]);

To change an entire string:

char something[] = "hello";
char *p = something;

while (*p) {
    *p = toupper(*p);
    p++;
}
cnicutar
  • 178,505
  • 25
  • 365
  • 392
  • It says: initializer fails to determine size of 'input' const char * input = "m"; char something[] = input; something[0] = toupper(something[0]); char *p = something; – John Jan 01 '12 at 16:18
  • @John That's not what I said :-) Read the answer again. Even better, look at Kerreks answer. – cnicutar Jan 01 '12 at 16:19
  • `p` is extraneous here -- use `something` only and the example will be much clearer IMO. – ildjarn Jan 01 '12 at 16:27
  • @ildjarn But I can't increment it. I would have to use a separate iterator. – cnicutar Jan 01 '12 at 16:29
  • @DietmarKühl I know. It's usually implemented with macros (I've seen it somewhere in Plauger) so passing it the wrong thing is undefined behavior. Edit my post if you like, I'll accept your edit. – cnicutar Jan 01 '12 at 17:27
5

You can use the same algorithmic approach that you know for std::string for raw arrays:

char s[] = "hello world";
std::transform(s, s + std::strlen(s), s, static_cast<int(*)(int)>(std::toupper));

You cannot do this for immutable string literals (like const char * s = "hello world;") for obvious reasons, so you won't get around an additional allocation/copy for that.

Update: As Ildjarn says in the comment, it's important to note that string literals are always read-only, even though for historical reasons you are allowed to bind them to a pointer-to-mutable, like char * s = "hello world";. Any decent C++ compiler should slap you in the face if you attempt this, but it is valid C++ -- but any attempt to actually modify any element of s is undefined behaviour.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 3
    I think it may be worth explaining more in-depth why `char * s = "hello world;"`, sans `const`, is also immutable -- this is a primary hangup for beginners. – ildjarn Jan 01 '12 at 16:26
  • @DietmarKühl: Good point; you should probably use the version of `toupper` that comes with `` for a more general solution. – Kerrek SB Jan 01 '12 at 17:31
  • @DietmarKühl: Nobody can keep up with zose crazy Germans :-) Now they *do* have a [capital SZ](http://en.wikipedia.org/wiki/Capital_ß), but it's not representable by a `char`... *sigh* – Kerrek SB Jan 01 '12 at 17:49
5

As explained in the very famous C book - The C Programming Language by Kernighan & Ritchie in section 5.5 Character Pointers and Functions,

char amessage[] = "now is the time";    /* an array */
char *pmessage = "now is the time";     /* a pointer */

`amessage` is an array, just big enough to hold the 
sequence of characters and `'\0'` that initializes it. 
Individual characters within the array may be changed 
but `amessage` will always refer to the same storage. 
On the other hand, `pmessage` is a pointer, initialized 
to point to a string constant; the pointer may subsequently 
be modified to point elsewhere, but the result is undefined
if you try to modify the string contents.

OTOH, in C, to convert to upper case letters, you can use the following program as a reference.

#include <stdio.h>
#include <ctype.h>

int main(void)
{
    int i=0;
    char str[]="Test String.\n";
    char c;

    while (str[i]) {
        c=str[i];
        putchar(toupper(c));
        i++;
    }

    return 0;
}

In C++

#include <iostream>
#include <string>
#include <locale>
using namespace std;

int main ()
{
    locale loc;

    string str="Test String.\n";

    for (size_t i=0; i<str.length(); ++i)
        cout << toupper(str[i],loc);

    return 0;
}

EDIT: Adding pointer version (as requested by @John) for the C version

#include <stdio.h>
#include <ctype.h>

int main(void)
{
    int i=0;
    char str[]="Test String.\n";
    char *ptr = str;

    while (*ptr) {
        putchar(toupper(*ptr));
        ptr++;  
    }   

    return 0;
}

Hope it helps!

Sangeeth Saravanaraj
  • 16,027
  • 21
  • 69
  • 98
  • @John could you please elaborate your question?! You mean, how to have a pointer point to an array? – Sangeeth Saravanaraj Jan 01 '12 at 16:26
  • @SangeethSaravanaraj, when you pass a `char` to the C toupper and other functions taking a character in an `int`, it must be first cast to an unsigned char and then to an `int`. – AProgrammer Jan 01 '12 at 16:36
2

You can convert C-string to std::string and then use boost::to_upper to change string in place or boost::to_upper_copy to create upper case copy of the string. Here is the code example:

#include <iostream>
#include <boost/algorithm/string/case_conv.hpp>

int main ()
{
  char const * s = "Test String.\n";
  std::string str(s);

  std::cout << boost::to_upper_copy(str).c_str() << std::endl;

  return 0;
}

Hope this helps.

mkostya
  • 922
  • 3
  • 10
  • 14
1

You could do:

#include <algorithm>
#include <iterator>
#include <ctype.h>

char test[] = "m";

std::transform(std::begin(test), std::end(test), std::begin(test), ::topper);

This applies the ::toupper function to character of the string. This is the ::toupper function in the global namespace that comes from C. std::toupper has multiple overloads and ::toupper looks more elegant than static_cast<int (*)(int)>(&std::toupper).

Antti Kivi
  • 103
  • 7