-2

When I do-

#include <iostream>

int main(){
    char *p = "Hello";
}

it works fine, but doing

#include <iostream>

int main(){
    char *p = 'H';
    // OR
    int *x = 5;

}

gives an error: invalid conversion from 'char' to 'char*' [-fpermissive] / 'int' to 'int*'

user123456789
  • 424
  • 4
  • 15
  • 4
    `char *p = "Hello";` is not supposed to compile. If you are using gcc use `-pedantic-erros` when compiling to turn off compiler extensions. (I really wish this was on by default). – NathanOliver Apr 10 '19 at 17:37
  • 1
    undefined behavior = works fine sometimes but is still undefined behavior – AndersK Apr 10 '19 at 17:38
  • @NathanOliver technically, it is valid but deprecated in C++03 – Brian Bi Apr 10 '19 at 17:39
  • 1
    The two different quotes do different things. Double quotes: `"A string of characters"` inclose a string of characters, which has a type of `char const*` while Single Quotes: `'X'` incluse a single character which has a type of `char`. – Martin York Apr 10 '19 at 17:40
  • 2
    @Brian True, but the C++ tag refers to the current standard (C++17) so my comment is correct. – NathanOliver Apr 10 '19 at 17:40
  • Note: `deprecated` means it is still valid. It just means that compiler should warn you that it is a bad idea. It will never be removed because it would break so much old code. So though Nathan is pedantically correct it is not relevant point that is muddying the actual discussion (and I would encourage him to remove his comments as it is confusing to a beginner). – Martin York Apr 10 '19 at 17:44
  • @MartinYork Pedantically, the type of `"A string of characters"` is not `const char*`, it is `const char[23]`. – Jesper Juhl Apr 10 '19 at 18:23
  • @NathanOliver the C++ tag doesn't refer to a specific version, that's why the tooltip for it suggests adding version-specific tags. – Tzalumen Apr 10 '19 at 18:47
  • @Tzalumen [It actually does](https://stackoverflow.com/tags/c%2b%2b/info): *Unless the question explicitly mentions which version of the C++ standard that is used, it is assumed that the current version is used. That is, whichever version of ISO 14882 that ISO currently lists as active. Please have this in mind when answering or commenting on questions tagged c++.* – NathanOliver Apr 10 '19 at 18:50
  • @NathanOliver why should char *p = "Hello"; not compile? "Hello" is an array of char so char* is valid – Dimfred Apr 10 '19 at 19:15
  • 1
    @Dimfred Because `"Hello"` is a `const char[N]` where `N` is the number of characters plus a null terminator. Doing `char* foo = "hello";` would strip the `const` off of the string literal so it should fail to compile as the only way to remove `const` is to use a c-style cast or `const_cast`. – NathanOliver Apr 10 '19 at 19:17
  • Ahh got it thx. – Dimfred Apr 11 '19 at 09:49
  • So the question in the title is actually a good question! – Mr Lister Apr 16 '19 at 06:15

1 Answers1

0

The issue here is that C++ is a strongly typed language. You have to make sure the type on the right of an = is the same as the type on the left (or there is some well defined conversion that allows the compiler to convert between types).

So we need to know what types literals are: Using a double quote creates a string literal of type char const[] while using a single quote creates a character literal of type char const.

You will have to bear with me on the const part. That makes the discussion much more complicates so we will gloss over it initially.

We also need to know that when arrays are used in expressions they very easily decay into pointers. So it most situations the type of char const[] will decay into char const*.

This should work:

char const* p = "Hello";    // This is valid.
                            // Both left and right sides have the same type.
                            // After you consider the array decay into a pointer.

On the other hand

char const* p = 'H';        // The type on the right is `char const'
                            // While the type on the right has a pointer in it.

Now there are some automatic conversions at play here.
In the original C++03 the compiler was allowed to auto convert string literals from char const* to char*. This is a relic from the old C language that was not as strict on type checking as C++ is now. This allows for this:

 char*       p = "Hello";    // Because there is an auto conversion
                             // the compiler is allowed to make 
                             // the conversion from one type to another

Note in later versions of C++ this conversion has been deprecated. SO the compiler will warn you that this is dangerous (because you have removed the const from the type you are allowed to modify it, but the underlying object can't be modified so if you try it will blow up the program).

So why can you assign char const to a char?

char  x = 'X';

Here you are copying the original object char const into an object of type char this is perfectly valid. You can not alter or chance the literal but you are allowed to make copies of it. So you can easily remove the outer const in an assignment expression.

 char const* const y = "Hello";
 char const*       z = y;        // We remove the outer const
                                 // from a pointer. But the inner
                                 // const (of the object being pointed
                                 // at) can not be removed so easily.

                                 // This works because z is allowed to 
                                 // to be changed but hold a value a pointer
                                 // to a value that can not be changed.

Looking at your comment:

#include <iostream>
void test(char *str)
{
    std::cout << str << std::endl;
}

int main()
{
    test("Hello");           // This is allowed in C++
                             // Deprecated still means valid.
                             // Just not a good idea

                             // There is a allowed conversion from
                             // char const* to char* for string literals.


    char const* x = "test";
    test(x);                 // This is NOT allowed.
                             // You can not cast away this const.
}

Note: Technically a string literal is char const[]. ie an array of const char. BUT when used in an expression arrays very easily decay into pointers and thus it is sometimes simpler to think of them as char const* but this thinking is abstract and you should know the underlying exact type.

Martin York
  • 257,169
  • 86
  • 333
  • 562
  • So doing this is also discarded (without using const)? - `#include void test(char *str){ std::cout << str << std::endl; } int main(){ test("Hello"); }` – user123456789 Apr 10 '19 at 18:01
  • `discarded` is the wrong word. Pick your words carefully. There is an automatic conversion from `char const*` to `char*` that the compiler is allowed to to apply to `string literals`. That works here. It does not apply to genericly typed objects. – Martin York Apr 10 '19 at 18:04
  • `double quote creates a string literal of type char const*` wrong, and the rest of explanation which is founded on this assumption is wrong too. – SergeyA Apr 10 '19 at 18:04
  • @SergeyA Care to explain? I am pretty certain that is the correct type of a string literal. Or are you saying that string literal is `char const[]`. – Martin York Apr 10 '19 at 18:08
  • @SergeyA Added a note at the first mention and exact definition at the bottom. – Martin York Apr 10 '19 at 18:14
  • Yes, they are of type `const char[]` and it is important. The way you structured your answer makes an incorrect claim in the very beginning, on which you build, and only in the very end you mention the correct definition. I disagree with that approach. I believe, the answer should use correct definitions all the way. – SergeyA Apr 10 '19 at 18:15
  • @SergeyA I am more than happy to make alterations to make this better. DO you want to discuss this? – Martin York Apr 10 '19 at 18:17
  • Well, the way I'd do it is to say what is it, and than base discussion on it. Truth it, it might not even be neccessary. There are plenty of duplicates: https://stackoverflow.com/questions/12517983/what-is-the-datatype-of-string-literal-in-c?noredirect=1&lq=1 https://stackoverflow.com/questions/3683602/single-quotes-vs-double-quotes-in-c-or-c possibly others. – SergeyA Apr 10 '19 at 18:20
  • Moved the definition to the top. Also added the important point of pointer decay. – Martin York Apr 10 '19 at 18:23
  • @SergeyA I read the other questions. They don't answer this question very well. Especially for a beginner as there is a lot of implied information (or information that is not relevant). This question provides context for this situation. – Martin York Apr 10 '19 at 18:54
  • All the more reason to prefer `std::string` over `const char[]`, no risk of confusion to be had. Not to mention that the `const char[]` created with `operator""()` has an implicit terminal `'\0'` – Tzalumen Apr 10 '19 at 18:57