24

Why can I not do this:

char* p = new char[10];

void SetString(char * const str)
{
    p = str;
}


SetString("Hello");

I have a const pointer to a char, why can I not assign the const pointer to another pointer?

It just seems illogical, as by assigning it to another pointer, you are not essentially violating the const-ness of the char pointer. Or are you?

EDIT: When I compile this it says "error C2440: '=' : cannot convert from 'char *const *__w64 ' to 'char *'"

(I'm attempting to understand a concept from a book I'm reading. Just cannot get the code to compile.

CODE:

int _tmain(int argc, _TCHAR* argv[])
{

    MyString *strg = new MyString(10);
    strg->SetString("Hello, ");

    MyString *secondstr = new MyString(7);
    secondstr->SetString("Tony");

    strg->concat(*secondstr, *strg);

}

CPP FILE:

#include "MyStringClass.h"
#include <string.h>
#include "stdafx.h"

#include "MyStringClass.h"

void MyString::concat(MyString& a, MyString& b)
{
    len = a.len + b.len;
    s = new char[len + 1];
    strcpy(s, a.s);
    strcat(s, b.s);
    delete [] s; 

}

void MyString::SetString(char * const str)
{
    s = str;
}

MyString::MyString(int n)
{
    s = new char[n+1];
    s[n+1] = '\0';
    len = n;
}

HEADER FILE:

#include <string.h>
#include <stdio.h>

class MyString
{
private:
    char* s;
    int len;
public:
    MyString(int n = 80);

    void SetString (char * const str);

    void concat (MyString& a, MyString& b);
};
Tony The Lion
  • 61,704
  • 67
  • 242
  • 415
  • 2
    There isn't anything wrong with that code, per se. Why not show us real code with real compile errors to solve a real problem? – GManNickG Jul 23 '10 at 08:38
  • In response to the edit, what is "compile this"...you haven't posted compilable code. :) Give us a small snippet of what you're compiling, exactly. – GManNickG Jul 23 '10 at 08:49
  • 4
    Oh my. This code violates about two basic principles of C++ programming for every line. I wouldn't know where to start telling you what's wrong with it. What book are you learning C++ from? Whatever it is, trash it and have a look at [The Definitive C++ Book Guide and List](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) before you write any other line. – sbi Jul 23 '10 at 09:05
  • Hm, how is this code being compiled? (Which compiler and what settings?) By the way, this code is littered with bits of errors. Is the book saying to do things like `_tmain`? – GManNickG Jul 23 '10 at 09:06
  • @GMan - He is using the MSVC compiler, I presume, because Windows main is named as _tmain. – DumbCoder Jul 23 '10 at 09:11
  • I somehow managed to compile it on MSVC. And I didn't do any changes except provided a blank body for your constructor. I don't get the error though. – DumbCoder Jul 23 '10 at 09:14
  • @DumbCoder: That's not necessarily true, `main` is the standard main and VS takes that just fine. `_tmain` is just one of many implementation-specific mains. I also get no error with default-ish settings in VS. – GManNickG Jul 23 '10 at 09:16
  • @Gman, @DumbCoder: I solved my problem, and yes this code has errors. The book was pointing out that you cannot just delete [] s where it is being deleted at that point. I wanted to see what happens when you do so... Crash boom, dead! Haha :) – Tony The Lion Jul 23 '10 at 09:24
  • @GMan - I never said VS only uses _tmain. I use main on VC++. Probably I should have worded it properly. – DumbCoder Jul 23 '10 at 09:24
  • The error message is not from that code! (or VS messed up something). Which line is it? – adf88 Jul 23 '10 at 09:41

1 Answers1

34

There is difference between constant pointer and pointer to constant. Constant pointer is a pointer (a number - memory address) that cannot be changed - it always point to the same object given via initialization:

int * const const_pointer = &some_int_var; // will be always pointing to this var
const_pointer = &some_other_var; // illegal - cannot change the pointer
*const_pointer = 2; // legal, the pointer is a pointer to non-const

Pointer to constant is a pointer whose pointed value cannot be changed:

const int * pointer_to_const = &some_int_var; // doesn't have to be always pointing to this var
pointer = &some_other_var; // legal, it's not a constant pointer and we can change it
*pointer = 2; // illegal, pointed value cannot be changed

You can always assign constant to variable i.e. const pointer to non-const pointer (a). You can cast pointer to non-const to a pointer to const (b). But you cannot cast pointer to const to a pointer to non-const (c):

int * pointer;
int * const const_pointer = &var;
const int * pointer_to_const;

/* a */
pointer = const_pointer; // OK, no cast (same type)

/* b */
pointer_to_const = pointer; // OK, casting 'int*' to 'const int*'

/* c */
pointer = pointer_to_const; // Illegal, casting 'const int*' to 'int*'

[EDIT] Below, this is not standard c++. However, this is common.[/EDIT]
String literal

"Hello"

is converted to constant pointer to const (const char * const):

char *pointer = "Hello"; // Illegal, cannot cast 'const char*' to 'char*'
char * const const_pointer = "Hello"; // Illegal, cannot cast 'const char*' to 'char*'
const char * pointer_to_const = "Hello"; // OK, we can assign a constant to a variable of the same type (and the type is 'const char*')
"Hello" = pointer_to_const; // Illegal cannot re-assign a constant

In above examples the second is your case. You tried to initialize pointer-to-non-const with a pointer-to-const when passing string literal as argument of your function. No matter if these pointers are constants or not, it's matter what do they point to.

Summary:
1) If you cast a pointer of some type to a pointer of another type, you cannot cast pointer-to-const to pointer-to-non-const.
2) If you have constant pointer, the same rules applies as to other constants - you can assign a constant to a variable but you cannot assign a variable to a constant (except initializing it).

// EDIT
As GMan pointed out, the C++98 standard (§4.2/2) allows to implicitly cast string literals (which are constant char arrays) to a non-const char pointer. This is because of backward compatibility (in C language there are no constants).

Of course such a conversion can lead to mistakes and compilers will violate the rule and show an error. However, GCC in compatibility mode shows only a warning.

pezy
  • 1,022
  • 2
  • 8
  • 27
adf88
  • 4,277
  • 1
  • 23
  • 21
  • 2
    This does contain some wrong information, leading to wrong results. A string literal is an [array of const char's](http://stackoverflow.com/questions/3303164/why-isnt-if-maya-maya-true-in-c/3303212#3303212), not a `const char*` (Though, since it's an array, it can decay into such). While it's true such an array cannot typically be implicitly converted to `char*`, string literals have this special conversion. (It's deprecated, and only exists for backwards compatibility.) So all three of your code examples are completely legal. – GManNickG Jul 23 '10 at 09:19
  • I wrote that "it is converted to a pointer", not "it is a pointer". It is converted to a pointer that points to the array you are saying about. And you are wrong - string literals cannot be implicitly converted to 'char*'. Maybe you are confused with char array initialization. – adf88 Jul 23 '10 at 09:29
  • 2
    No, I'm not. §4.2/2: "A string literal (2.13.4) that is not a wide string literal can be converted to an rvalue of type “pointer to char”; a wide string literal can be converted to an rvalue of type “pointer to wchar_t”. In either case, the result is a pointer to the first element of the array. This conversion is considered only when there is an explicit appropriate pointer target type, and not when there is a general need to convert from an lvalue to an rvalue. [Note: this conversion is deprecated. See Annex D. ]" Like I said, all three lines are legal. (Well, you have four now; the first 3.) – GManNickG Jul 23 '10 at 09:47
  • Yes, you right. I missed the point. I'm young so this is really deprecated to me. Of course, for compatibility with C, string literals can be casted to non-const char pointer (only this kind of pointers exist in C). But either GCC and VC (and other compilers) are violating these rule and will show an error ('gcc -ansi -pedantic' shows warning). Well, I'll just give a note. – adf88 Jul 23 '10 at 10:02
  • *Pointer to constant is a pointer whose pointed value cannot be changed* - We cannot know. A pointer to `const` may point to an object that is not `const`. In that case the value of the object **can** be changed, directly by assigning to the object, or through another pointer that is not a pointer to `const`. It is not guaranteed that an object pointed to by a pointer to `const` won't change. – Khalida Aliyeva May 12 '20 at 19:38
  • @4klvlh You got me there... a pointer to a constant type `int const* ptr` the underlying value `*ptr` **can not** be changed directly by assigning a new value to the object because its type is integer constant, but you can make it appear **as if** the underlying value of the object had changed by making the `int const* ptr` point to a **different** object of the same type `int const` with a different underlying value. Note: What we really have are two different objects not one with a changing value. The only thing that changes is to which object we made `int const* ptr` point. – abetancort Jul 10 '20 at 21:24