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?
答案 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::cout
是std::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"
。在这一行中,c
是char
类型的变量,您分配的是string
(hello world)。所以,它会失败。
其次,
*pi
会为您提供pi
指向的变量的值,但在char *
的情况下,*pc
会给出第一个字符的值字符串(表示“hello world”*pc
指向字符串中的第一个字符)。
如果你pc[1]
它会给你字符串中的第二个字符,但pc
表示整个字符串。