Is const char * different from other pointers?

时间:2018-01-23 19:39:37

标签: c++ string pointers

So I've been digging into pointers and references recently because they're used constantly in the resources I've been using to learn OpenGL. I've noticed that the const char * pointer seems to behave somewhat differently than other pointers. To demonstrate, I've created this test program:

#include <iostream>

int main() {

    int i = 2; 
    int *pi;
    //const char c = "hello world"; 
    const char *pc = "hello world";

    pi = &i;

    std::cout << "'hello world' type is " << typeid("hello world").name() << std::endl;

    std::cout << "pi is " << pi << std::endl;
    std::cout << "*pi is " << *pi << std::endl;

    std::cout << "pc is " << pc << std::endl;
    std::cout << "*pc is " << *pc << std::endl;



    return 0;
}

output:

'hello world' type is char const [12]
pi is 0079FC38
*pi is 2
pc is hello world
*pc is h

This result is confusing to me for several reasons. First, the commented out line const char c = "hello world" fails completely; why? By looking at the output, we can see that the type associated with "hello world" itself is char const [12]. Interestingly enough, the following line does work. But, the output is not what I would expect when compared with the output associated with the int pointer (pi). I.e. why when I print pc is the output hello world and not a memory address? (less important) And then, why when I print *pc is the output only the first element of the data contained at that address?

4 个答案:

答案 0 :(得分:3)

不,指向const char *的指针与其他指针的工作方式不同。

代码的不同之处在于C ++输出流(特别是)如何处理const char *与处理其他指针的方式。它通过提供operator<<()的明显重载来实现此目的。

一次重载需要const char *作为参数,ASSUMED指向nul终止的char数组(这是字符串文字如"Hello World"在内存中的表示方式)并且每char输出一次,直到达到那个为止。

另一个重载接受void *,并简单地输出该值(即地址)。这依赖于将指针类型隐式转换为void *

因此const char *与其他指针的行为不同。事实上,C ++输出流以不同于其他指针的方式处理const char *(通过提供执行不同操作的不同重载)。

注意:严格来说,如果要打印地址,则应该

std::cout << "pi is " << (void *)pi << std::endl;
std::cout << "pc is " << (void *)pc << std::endl;

将以相同的方式处理两个指针(即打印地址,而不是那些地址的数据),因为这两个指针随后使用相同版本的operator<<()打印。

答案 1 :(得分:1)

类型char *经常用于表示“非托管字符串”,即由'\0'字符终止的字符序列(与类std::string形成对比,包装这样一个“非托管”字符串)。所以cout负责这种常见的用法,因为它为类型char *提供了一个重载,它将值视为内存地址而不是指向字符序列的指针。 但这只是(普通的)函数重载,并且 - 除了一些关于对齐的特殊处理之外 - 指向char的指针和指向int的指针之间没有区别。

答案 2 :(得分:0)

  

首先,注释掉的行const char c = "hello world"失败   彻底;为什么?通过查看输出,我们可以看到类型   与“hello world”本身相关联的是char const [12]

因为数组与单个对象不同。您也无法使用int初始化int const[12]

  

为什么当我打印pc是输出问候世界而不是内存地址?

std::coutstd::ostream类型的对象,它是std::basic_ostream模板类的实例化,其中operator<<具有成员void const*函数:

http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt(重载7)

该函数允许将每个指针打印为一个地址,因为每个指针都可以转换为void const*。因此,为int*选择此重载。

char const*之所以特别,是因为std::basic_ostream还有重载非成员operator<< 各种char*变体的功能,其中一个优先于你的例子:

http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt2

operator<<的重载非成员char const*期望指针指向以null结尾的字符数组的第一个字符,并相应地执行输出操作。

正如您所看到的,它是使char const*与此特定情况下的其他指针不同的库,而不是核心语言。

  

然后,为什么当我打印*pc时输出只是第一个元素   该地址包含的数据?

因为*pc产生char而不是指针,所以选择了非成员operator<<的不同重载。

如果operator<<实际上使用了char& 并且获取了char的地址,以便将其视为空终止字符数组,那么混乱会随之而来;像std::cout << 'X';这样简单的事情会导致未定义的行为。

你可能会认为在相反的方向存在同样的问题:

#include <iostream>

int main()
{
    char c = 'X';
    char cc = 'Y'; // for more astonishing effect in practice, especially
                   // when compiled without optimisation

    std::cout << &c; // undefined behaviour
}

这是真的;这样的错误可能发生。但我认为能够写std::cout << "Hello world";的有用性超过了成本。

答案 3 :(得分:0)

首先。指针可能会在你不想要的时候真正混淆。

现在,第一个问题。

const char c = "hello world"。在这一行中,cchar类型的变量,您分配的是string(hello world)。所以,它会失败。

其次,

*pi会为您提供pi指向的变量的值,但在char *的情况下,*pc会给出第一个字符的值字符串(表示“hello world”*pc指向字符串中的第一个字符)。

如果你pc[1]它会给你字符串中的第二个字符,但pc表示整个字符串。