assigning string constant to char *

Discussion in 'C++' started by Steve Pope, Aug 25, 2006.

  1. Steve Pope

    Steve Pope Guest

    The first of the following functions compiles, the second gives what
    I think is a spurious error:

    "cannot convert `const char[5]' to `char *' in assignment".

    void foo(int m) {
    char *str;
    if (m < 4) str = "%01x";
    else if (m < 9) str = "%02x";
    else str = "%03x";
    }

    void foo(int m) {
    char *str;
    str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
    }

    Any idea why gcc doesn't like the second version? If I compile
    it as a C file instead of C++, it works fine.

    Steve
     
    Steve Pope, Aug 25, 2006
    #1
    1. Advertising

  2. Steve Pope wrote:

    > The first of the following functions compiles, the second gives what
    > I think is a spurious error:
    >
    > "cannot convert `const char[5]' to `char *' in assignment".
    >
    > void foo(int m) {
    > char *str;
    > if (m < 4) str = "%01x";
    > else if (m < 9) str = "%02x";
    > else str = "%03x";
    > }
    >
    > void foo(int m) {
    > char *str;
    > str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
    > }
    >
    > Any idea why gcc doesn't like the second version? If I compile
    > it as a C file instead of C++, it works fine.


    It is not a spurious error, just an obscure one. A string constant
    (like "%01x") is actually of type const char[5], which decays to const
    char*. For historical reasons (so as not to break a lot of existing
    code), you can assign a string constant to a non-const char*, although
    it bends (if not breaks) const-correctness. In the first example, you
    are assigning a string constant to a char*, and that's permitted. In
    the second example, you are assigning not a string constant, but an
    expression instead, to the char*. That's not permitted - the exception
    to const-correctness is intentionally kept narrow.

    To solve your problem change your second example to the following:

    void foo(int m) {
    const char *str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
    }

    Since you're now assigning to a const char*, not to a non-const char*,
    the problem disappears.

    Best regards,

    Tom
     
    Thomas Tutone, Aug 25, 2006
    #2
    1. Advertising

  3. Steve Pope

    Steve Pope Guest

    Thomas Tutone <> wrote:

    >Steve Pope wrote:


    >> void foo(int m) {
    >> char *str;
    >> str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
    >> }


    >> Any idea why gcc doesn't like the second version? If I compile
    >> it as a C file instead of C++, it works fine.


    >It is not a spurious error, just an obscure one. A string constant
    >(like "%01x") is actually of type const char[5], which decays to const
    >char*. For historical reasons (so as not to break a lot of existing
    >code), you can assign a string constant to a non-const char*, although
    >it bends (if not breaks) const-correctness. In the first example, you
    >are assigning a string constant to a char*, and that's permitted. In
    >the second example, you are assigning not a string constant, but an
    >expression instead, to the char*. That's not permitted - the exception
    >to const-correctness is intentionally kept narrow.


    Okay, that makes sense.

    >To solve your problem change your second example to the following:


    >void foo(int m) {
    >const char *str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
    >}


    >Since you're now assigning to a const char*, not to a non-const char*,
    >the problem disappears.


    That works, but oddly so does the following:

    const char *str;
    str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
    if (m > 12) str = "%04x";

    It seems the "const" does not mean as much for type char * as
    it does for other types.

    Steve
    >
    >Best regards,
    >
    >Tom
    >
     
    Steve Pope, Aug 25, 2006
    #3
  4. Steve Pope

    zeppe Guest

    Steve Pope wrote:

    > It seems the "const" does not mean as much for type char * as
    > it does for other types.


    It's an issue related not to the char type, but to the string literals:
    the following conversion are allowed:
    string literal -> const char*
    string literal -> char* // deprecated, but valid

    but, of course, it's not valid
    const char* -> char*

    so, you can convert string literal to char* only directly, not through
    const char* (as you tried with the conditional operator '?').

    Bye,

    Zeppe
     
    zeppe, Aug 25, 2006
    #4
  5. Steve Pope

    peter koch Guest

    Steve Pope skrev:

    [snip]
    >
    > Okay, that makes sense.
    >
    > >To solve your problem change your second example to the following:

    >
    > >void foo(int m) {
    > >const char *str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
    > >}

    >
    > >Since you're now assigning to a const char*, not to a non-const char*,
    > >the problem disappears.

    >
    > That works, but oddly so does the following:
    >
    > const char *str;
    > str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
    > if (m > 12) str = "%04x";
    >
    > It seems the "const" does not mean as much for type char * as
    > it does for other types.


    Well no.... as Thomas Tutone explained, you can break constness for
    char only. But what surprises you above is that you can reassign str.
    This is because you read the type wrongly. const char *str means that
    str is a pointer to a constant char. The pointer is by itself not
    constant - you can assign it to anything you want (and actually you
    should be surprised by both assignments above). If you wanted the
    pointer to be constant, the notation would have to be char * const str
    (and then you better remember to initialise it!). This way the content
    of *str would be changeable.

    /Peter
    >
    > Steve
    > >
    > >Best regards,
    > >
    > >Tom
    > >
     
    peter koch, Aug 25, 2006
    #5
  6. Steve Pope wrote:
    > Thomas Tutone <> wrote:


    [snip]

    > >It is not a spurious error, just an obscure one. A string constant
    > >(like "%01x") is actually of type const char[5], which decays to const
    > >char*. For historical reasons (so as not to break a lot of existing
    > >code), you can assign a string constant to a non-const char*, although
    > >it bends (if not breaks) const-correctness. In the first example, you
    > >are assigning a string constant to a char*, and that's permitted. In
    > >the second example, you are assigning not a string constant, but an
    > >expression instead, to the char*. That's not permitted - the exception
    > >to const-correctness is intentionally kept narrow.

    >
    > Okay, that makes sense.
    >
    > >To solve your problem change your second example to the following:

    >
    > >void foo(int m) {
    > >const char *str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
    > >}

    >
    > >Since you're now assigning to a const char*, not to a non-const char*,
    > >the problem disappears.

    >
    > That works, but oddly so does the following:
    >
    > const char *str;
    > str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
    > if (m > 12) str = "%04x";
    >
    > It seems the "const" does not mean as much for type char * as
    > it does for other types.


    Sorry, my changing your example so that the str was initialized upon
    creation confused matters. A const char* means "a pointer to a char
    that is const," not "a const pointer to a char." The latter would be
    char* const. You can reassign a const char*, you just can't change the
    contents of what it points to.

    Best regards,

    Tom
     
    Thomas Tutone, Aug 25, 2006
    #6
  7. Steve Pope wrote:
    > Thomas Tutone <> wrote:

    [..]
    >> To solve your problem change your second example to the following:

    >
    >> void foo(int m) {
    >> const char *str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
    >> }

    >
    >> Since you're now assigning to a const char*, not to a non-const
    >> char*, the problem disappears.

    >
    > That works, but oddly so does the following:
    >
    > const char *str;
    > str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
    > if (m > 12) str = "%04x";
    >
    > It seems the "const" does not mean as much for type char * as
    > it does for other types.


    You confuse your consts. In

    const char * str;

    'const' relates to the char, not to the char*. You need to read up on
    declaration syntax and its meaning.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Aug 25, 2006
    #7
  8. Steve Pope

    Steve Pope Guest

    zeppe <> wrote:

    >Steve Pope wrote:


    >> It seems the "const" does not mean as much for type char * as
    >> it does for other types.


    > It's an issue related not to the char type, but to the string
    > literals: the following conversion are allowed:


    > string literal -> const char*
    > string literal -> char* // deprecated, but valid
    >
    >but, of course, it's not valid
    >const char* -> char*
    >
    >so, you can convert string literal to char* only directly, not through
    >const char* (as you tried with the conditional operator '?').


    Seems that *is* related to the type char *, since the following
    code also compiles, whereas analogous code with str of any type
    other than char * does not compile. To me it looks like gcc
    at least has special-cased "const char *" to not actually be const.

    char a[10], b[10];

    void foo(int m) {
    const char *str;
    str = a;
    if (m > 12) str = b;
    }

    Cheers,


    Steve
     
    Steve Pope, Aug 25, 2006
    #8
  9. Steve Pope wrote:
    > [..] To me it looks like gcc
    > at least has special-cased "const char *" to not actually be const.
    >
    > char a[10], b[10];
    >
    > void foo(int m) {
    > const char *str;
    > str = a;
    > if (m > 12) str = b;
    > }


    There you go again... 'str' is a non-const pointer to const char.
    You can assign new value to it from an array (which when used in
    an exrpession like assignment above decays to a pointer to char).

    If you want 'str' to be non-changeable pointer, you need to declare
    *it itself* const:

    char * const str;

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Aug 25, 2006
    #9
  10. Steve Pope

    zeppe Guest

    Steve Pope wrote:

    >> but, of course, it's not valid
    >> const char* -> char*


    > Seems that *is* related to the type char *, since the following
    > code also compiles, whereas analogous code with str of any type
    > other than char * does not compile. To me it looks like gcc
    > at least has special-cased "const char *" to not actually be const.
    >
    > char a[10], b[10];
    >
    > void foo(int m) {
    > const char *str;
    > str = a;
    > if (m > 12) str = b;
    > }


    Actually, this is the opposite cast, i.e.:
    char* -> const char*

    that of course is correct (and the above code works also with int*,
    double* and any other pointer).
    BTW, it seems that we are talking about two different things: I was
    explaining the strange behaviour due to the conversion from literal to
    char*, and you are referring to the fact that is seems possible o change
    value to a const variable (that is, as others explained, is not const,
    but it's const the value the pointer is referring to).


    Bye,

    Zeppe
     
    zeppe, Aug 26, 2006
    #10
  11. Steve Pope

    Steve Pope Guest

    peter koch <> wrote:

    >But what surprises you above is that you can reassign str.
    >This is because you read the type wrongly. const char *str means that
    >str is a pointer to a constant char. The pointer is by itself not
    >constant - you can assign it to anything you want (and actually you
    >should be surprised by both assignments above). If you wanted the
    >pointer to be constant, the notation would have to be char * const str
    >(and then you better remember to initialise it!).


    Thanks, that does explain my confusion here.

    Steve
     
    Steve Pope, Aug 26, 2006
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Senthilraja

    Assigning string constant to char* without malloc

    Senthilraja, Aug 25, 2003, in forum: C Programming
    Replies:
    3
    Views:
    592
    Ben Pfaff
    Aug 25, 2003
  2. Replies:
    4
    Views:
    339
    Keith Thompson
    Dec 14, 2006
  3. sinbad
    Replies:
    7
    Views:
    661
    sinbad
    Jun 19, 2008
  4. dev
    Replies:
    2
    Views:
    372
    Eric Sosman
    Apr 17, 2009
  5. weston
    Replies:
    1
    Views:
    254
    Richard Cornford
    Sep 22, 2006
Loading...

Share This Page