12

Whey we cannot Convert pointer to a character ->TO-> a reference to a pointer to a constant character

I am interested in knowing the reason of syntax error when we call foo_ptr. When foo_char is allowed why not foo_ptr.
[Update 1.] I would be happy in knowing the reason that foo_char() is working, why foo_ptr() is not working .. What happens when pointer come in the picture.

[Update 2.] Didnt work in Dev C++ compiler version 4.9.9.2 too ..

//code
//OS : Win XP
//Env: VC++ 2008 

//NOT ALLOWED
void foo_ptr(const char * & ptr) //reference to a pointer to a constant character         
{         
        return;         
}        


//allowed        
void foo_char(const char & p_Char) //reference to a constant character        
{         
        return;        
}        

int main()        
{        
        char ch = 'd';        
        char *ptr =  "anu";        

        foo_char(ch);         
        foo_ptr(ptr); //NOT ALLOWED syntax error, vc++, 2008        

        return 0;        
}        
anubhav16
  • 238
  • 3
  • 11

3 Answers3

10

Suppose you had

void foo_ptr(const char * & ptr)
{         
    ptr = "readonlystring";
}        

You now call it as

    char *ptr;
    foo_ptr(ptr);
    *ptr = 0;

Suppose no error were raised. You are writing to a read-only string, violating the type system without any casts.

This is basically the CV version of How come a pointer to a derived class cannot be passed to a function expecting a reference to a pointer to the base class?.

Community
  • 1
  • 1
Raymond Chen
  • 44,448
  • 11
  • 96
  • 135
  • Good point. But you can do that with `typedef char* CHARPTR` anyway already. – Eric Z Oct 21 '11 at 15:03
  • 1
    Not sure what you mean. Changing `char *ptr` to `CHARPTR ptr` would still raise an error. – Raymond Chen Oct 21 '11 at 15:04
  • What's the error? Replacing `char*` w/ typedef in OP's code should compile successfully. – Eric Z Oct 21 '11 at 15:09
  • 2
    Oh, you mean replacing it in foo_ptr. That's because `const char *&` is not the same as `const CHARPTR&`. The former is a reference to a pointer to a `const char`. The latter is a const reference to a pointer to a `char`. So it's a different function. – Raymond Chen Oct 21 '11 at 15:20
  • I intend to write function only to read the value from reference to a pointer not to write into it. The concern is not on the application part, but to explore the behavior of C++. The error came as: error C2664: 'foo_ptr' : cannot convert parameter 1 from 'char *' to 'const char *&' – anubhav16 Oct 21 '11 at 15:23
  • C++ doesn't prevent such kind of mistakes. char* p= "blahblahblah"; p[0]=0; is legal (unfortunately) – user396672 Oct 21 '11 at 15:34
  • 1
    @user976141, then what you really need is `char * const &` or `const char * const &`. – Eric Z Oct 21 '11 at 15:35
  • @EricZ :Thanks again, char * const &, I guess is not a reference to a pointer to a constant character, its close reference to a constant pointer. I guess I was little reserved while explaining. I would be happy in knowing the reason that foo_char() is working, why foo_ptr() is not working .. What happens when pointer come in the picture. – anubhav16 Oct 21 '11 at 16:00
  • Sorry, the example in my previous comment is depricated. I agree with Raymond. Parameter, passing by reference is (potentially) output parameter, so the rules for the parameter(constness) must be the same as for function return value – user396672 Oct 21 '11 at 16:05
  • @RaymondChen: Thanks again. Very much appreciable. I did not understand the comment. foo_ptr(const char * & ptr) : i guess is a reference to a pointer to a constant character. and foo_char() : reference to a constant character. At least, thats what I meant. Please let me know if the actual declaration syntax and my understanding of these declarations mismatched. – anubhav16 Oct 21 '11 at 16:51
  • @anubhav16: oh, pointer is exactly the same. the parameter of `foo_char` is a reference to const char but the parameter of `foo_ptr` is not a reference to const pointer, it's a reference to pointer to const char. That's the point. If it were a reference to const pointer(as I did w/ typedef), it should work fine as `foo_char`. – Eric Z Oct 21 '11 at 16:55
  • +1: This is the correct answer. Also, if you want to fix this to get the behavior you are expecting change the parameter to `const char * const & ptr` – James Oct 21 '11 at 17:07
2

Revised with more examples: Raymond Chen provides the correct answer. By passing a non const pointer (char *) as reference parameter of a const pointer (foo_ptr(const char * &param)) you risk returning a const pointer type (const char *) and the compiler won't allow you to do that.

Here's Raymond Chen's example of that, but I tried to explain how things would go wrong if it compiled by adding additional comments and code:

void foo_ptr(const char * & ptr)
{         
    //Valid assignment, and the char * is now pointing to a const
    //array of "readonlystring"
    ptr = "readonlystring";
}   

...
//inside main
char *ptr = malloc(10*sizeof(char));
//See you can edit ptr, it's not const.
ptr[0] = 'a';
ptr[1] = 'b';
//this should not compile, but lets assume it did..
foo_ptr(ptr);
//Oh no, now ptr[0] is 'r' inside of constant memory,
//but now since ptr isn't declared const here I can overwrite it!
//But luckily most (all?) compilers actually fail to compile this code.
ptr[0] = 'b';

But if you change your parameter so you can't affect the value that the pointer points to then the compiler will let you past in a non-const because there is no chance a const valued pointer is returned.

By placing the keyword const AFTER the * in your parameter deceleration you do just that. That means change:

void foo_ptr(const char * & ptr)

to

void foo_ptr(const char * const & ptr)

and your compiler will be happy.

Now you would not be able to do something like ptr = "readonlystring" in the above example because that would never compile now. Based on your question that should be OK because you would not be able to do the assignment to a const char & in your original example.

Community
  • 1
  • 1
James
  • 1,754
  • 14
  • 22
  • Eric and @James : Thank you so much guys. To me, this sounds better than any other answered here [at least to my understaning]. I am novice and It would be really helpful if a bit detail in explaination with example(s) can be added here to help us understand this completely. (or any source/link would also work equally). .... I gave a lot of thought esp on the line "....const array pointer you risk returning a const pointer type".. but couldnt feel satisfied.. Thanks a lot for the time and effort. – anubhav16 Oct 21 '11 at 21:26
  • I revised the answer with some more code and explanation. Hopefully the snippets I added to explain the line that confused you will help. – James Oct 21 '11 at 21:56
  • Great.. I now.. understood. Thanks a lot :). I appreciate the efforts and time you spent. Many thanks again. – anubhav16 Oct 22 '11 at 05:52
  • [Update 3.] My doubt is resolved. I am satisfied. Thanks to every one for their time and efforts in helping me. Esp. I would like to thank Raymond(who was right but I did not understand his point at the first time), Eric Z(Who added more values) and finally James who explained Eric's point with detailed example. Thanks a lot guys. James- Thanks for closing this post (at least from my side.). – anubhav16 Oct 22 '11 at 06:06
  • 1
    Hmm, I'm not sure why I thought it was Eric I was quoting, it was [Raymond Chen](http://stackoverflow.com/users/902497/raymond-chen) – James Oct 23 '11 at 15:43
0

You should never assign a string literal to a non-const char pointer, as you do here:

 char *ptr =  "anu";        

Change the above to correct code:

 const char *ptr =  "anu";        

...and I think you'll find your problems are solved.

John Dibling
  • 99,718
  • 31
  • 186
  • 324