常量字符 * 与其他指针不同
Is const char * different from other pointers?
所以我最近一直在研究指针和引用,因为它们在我用来学习OpenGL的资源中经常使用。我注意到const char *
指针的行为似乎与其他指针有些不同。为了演示,我创建了这个测试程序:
#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;
}
输出:
'hello world' type is char const [12]
pi is 0079FC38
*pi is 2
pc is hello world
*pc is h
由于几个原因,这个结果让我感到困惑。首先,注释掉的行const char c = "hello world"
完全失败;为什么?通过查看输出,我们可以看到与"hello world"本身关联的类型是char const [12]。有趣的是,以下行确实有效。但是,与与int
指针(pi
)关联的输出相比,输出不是我所期望的。即为什么当我打印pc
时输出hello world
而不是内存地址?(不太重要)然后,为什么当我打印*pc
时,输出只是该地址中包含的数据的第一个元素?
不,指向const char *
的指针与其他指针的工作方式不同。
代码中的不同之处在于C++输出流(特别是)如何处理const char *
与如何处理其他指针。 它通过提供不同的operator<<()
重载来实现这一点。
一个重载将const char *
作为参数,假设它指向一个以 nul 结尾的char
数组(这就是像"Hello World"
这样的字符串文字在内存中的表示方式)并输出每char
一次,直到达到该 NUL。
另一个重载接受void *
,并简单地输出值(即地址)。 这依赖于将指针类型隐式转换为void *
。
因此,与其他指针行为不同的不是const char *
。 事实上,C++输出流处理const char *
的方式与其他指针不同(通过提供执行不同操作的不同重载)。
注意:严格来说,如果要打印地址,则应这样做
std::cout << "pi is " << (void *)pi << std::endl;
std::cout << "pc is " << (void *)pc << std::endl;
这将以相同的方式处理两个指针(即打印地址,而不是这些地址的数据),因为然后使用相同版本的operator<<()
打印两个指针。
char *
类型(非常)经常用于表示"非托管字符串",即以' '
字符结尾的字符序列(与类std::string
相反,它包装了这样的"非托管"字符串)。所以cout
照顾了这种常见的用法,因为它为类型char *
提供了一个重载,它不将值视为内存地址,而是将值视为指向字符序列的指针。 但这只是(普通)函数重载,并且 - 除了一些关于对齐的特殊处理 - 指向字符的指针和指向 int 的指针之间没有区别。
首先,注释掉的行
const char c = "hello world"
失败 完全;为什么?通过查看输出,我们可以看到类型 与"Hello World"本身相关的是Char Const[12]
因为数组与单个对象不同。您也不能用int const[12]
初始化int
。
为什么当我打印时
pc
输出是hello world而不是内存地址?
std::cout
是一个类型std::ostream
的对象,它是std::basic_ostream
模板类的实例化,该类具有用于void const*
的成员operator<<
函数:
http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt(过载 7)
该函数允许将每个指针打印为地址,因为每个指针都可以转换为void const*
。因此,为您的int*
选择此重载。
char const*
很特别std::basic_ostream
因为它还为各种char*
变体重载了非成员operator<<
函数,其中一个函数在您的示例中优先:
http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt2
char const*
的重载非成员operator<<
期望指针指向以 null 结尾的字符数组的第一个字符,并相应地执行输出操作。
如您所见,正是库使char const*
与这种特定情况下的其他指针不同,而不是核心语言。
然后,为什么当我打印
*pc
时输出只是第一个元素 该地址包含的数据是什么?
由于*pc
产生char
而不是指针,因此选择了非成员operator<<
的不同重载。
如果operator<<
实际上采用char&
并获取char
的地址,以便将其视为以 null 结尾的字符数组,那么混乱就会随之而来;像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";
的有用性超过了成本。
首先。指针在您不希望它们出现的时候可能会非常令人困惑。
现在,对于第一个问题。
const char c = "hello world"
.在这一行中,c
是char
类型的变量,您为其分配的是一个string
(hello world)。所以,它会失败。
第二
*pi
会给你pi
指向的变量的值,但在char *
的情况下,*pc
给出字符串中第一个字符的值(这意味着在"hello world"中*pc
指向字符串中的第一个字符)。
如果你这样做pc[1]
它会给你字符串中的第二个字符,但pc
表示整个字符串。
- 结构和双指针隐藏在其他结构中,多层混淆
- 这个失败的测试是将零添加到空指针未定义的行为、编译器错误还是其他什么?
- 包含指向其他结构的指针向量的结构
- 我可以使用 decltype() 或其他东西通过指针获取真实类型吗?
- 在指针中对其他信息进行编码
- char* 除了作为C++中的指针之外,还有其他功能吗?
- C++ 指向其他类函数的指针函数
- 当动态库中的指针仍被其他库使用时,如何删除该指针
- 指向用随机指针归档的其他类对象的指针的c++向量
- Sizeof返回的是指针大小,而不是数组大小.有其他方法可以找到尺寸吗
- 如何知道指针是否已在其他地方释放
- 为什么C++让你把"->"符号放在指针上,把"."符号放在其他所有东西上?
- fprintf 不打印到文件,当文件指针在其他地方声明时
- QPointer::clear() 是删除其引用的指针,还是"Clears this QPointer object."其他含义?
- 与其他语言相比的 Ruby 和指针
- 如何在没有作弊引擎的情况下从其他应用程序获取指针地址?
- 为什么可以将所有类型转换为其他指针类型?
- 将指针类方法作为参数传递给其他类方法C
- 将指针与其他数据相关联
- 如何复制包含指向其他几个成员之一的指针的对象?