6
#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
    char array[10];

    for(int i = 0; i<10;i++)
    {
        array[i] = 'a' + i;
    }

    char* test = array;

    printf("%x\n", test);
    cout << hex << test << endl;

}

输出是:

bffff94e
abcdefghijN???

为什么不打印相同的东西?

4

4 回答 4

7
cout << hex << test << endl; 

它打印字符串,而不是地址。这是因为有一个作为参数的重载,operator<<并且char const*此重载将参数视为字符串。

如果要打印地址,请将参数转换为,void*以便调用其他重载operator<<来打印地址。

cout << hex << static_cast<void*>(test) << endl;

将以十六进制格式打印地址。

请注意,hex此处不需要流操纵器,因为地址将以十六进制格式打印。所以

cout << static_cast<void*>(test) << endl;

足够的。

于 2012-06-19T06:43:13.950 回答
6

因为您的程序具有未定义的行为。因为你要求它打印不同的东西。

您的调用printf是非法的,并且会导致未定义的行为(并且是一个很好的例子,说明了为什么您永远不应该使用printf)。您的格式说明符说unsigned int从参数列表中提取一个,并以十六进制输出。传递它除了 an 之外的任何东西unsigned int都是未定义的行为。碰巧的是,考虑到 varargs 通常实现的方式,如果你在一台 unsigneds 和指针大小相同的机器上,你可能会输出指针的值,把它的位当作一个unsigned. 然而,其他行为当然是可能的。(如果我没记错的话,g++ 会警告这个结构;在某些平台上,它也可能会崩溃。)

在 的情况下std::cout,您将通过char*. 根据定义, thechar*被视为 '\0' 字符串,而不是指针(当然也不是unsigned int)。再一次,你有未定义的行为,因为你char*没有指向一个 '\0' 终止的字符串;你永远不会在最后放一个 '\0' 。(这可能解释了"N???" 您在输出末尾看到的情况。但同样,未定义的行为是未定义的。代码很容易崩溃。)

最后,您同时使用printfand std::cout; 除非您对两者之间的流进行刷新,否则不会真正指定结果。(实际上,如果您要输出到交互式设备,则应在输出'\n'字符时进行刷新。但是,如果将输出重定向到文件,则可能会得到不同的结果。)

不清楚你想要什么。如果要输出 的地址 array,则为:

printf( "%p\n", test );
std::cout << static_cast<void*>( test ) << std::endl;

如果要输出生成的字符串,请在其末尾附加一个 '\0' (不会溢出缓冲区),然后:

printf( "%s\n", test );
std::cout << test << std::endl;

我不确定您要制作什么“十六进制”;没有字符串的十六进制表示,指针的表示是实现定义的,不需要考虑 iostream 中的任何格式参数。(通常,在大多数现代机器上,它将是十六进制的。但我已经研究过不止一些它是八进制的,并且至少有一个它不仅仅是一个数字,不管基数如何。)如果你想要一个十六进制转储array,你必须循环,将每个值输出为unsigned十六进制:

for ( int i = 0; i < 10; ++ i ) {
    printf( "%x", static_cast<unsigned char>( test[i] ) );
}
printf( "\n" );
std::cout.setf( std::ios_base::hex, std::ios::basefield );
for ( int i = 0; i < 10; ++ i ) {
    std::cout << static_cast<unsigned>( static_cast<unsigned char>( test[i] ) );
}
std::cout.setf( std::ios_base::dec, std::ios::basefield );
std::cout << std::endl;

最后:关于演员表:plainchar可以是有符号的也可以是无符号的;如果它是有符号的,将其转换为 anint或 an unsigned,可能会产生一个负值 ( int) 或一个非常大的正值 ( unsigned)。因此,第一次转换为 unsigned char,这保证了范围内的结果[0, UINT_MAX]。其次,当然,我们必须将其转换unsigned charunsigned

  • 在 的情况下printf,因为否则我们会有未定义的行为,但是转换是隐式的,因为将 anunsigned char作为可变参数传递会自动将其提升为unsigned; 和

  • 在这种情况下std::cout,因为规则是任何字符类型都作为字符而不是数值输出(并且由于该类型在函数重载决议中使用,并且没有传递给 vararg 或 an unsigned,所以没有隐式转换)。

于 2012-06-19T07:47:00.603 回答
2

test它本身是一个指针,即它存储一个地址。您的printf语句打印该地址的十六进制值。

然后该cout <<语句打印整个字符串,因为std::hex操纵器不会影响字符串的打印方式。它只影响整数的打印方式。

你能做的是

  1. 循环遍历数组的字符
  2. 将每个转换为整数并使用std::hex操纵器打印

看起来像这样:

for (int i = 0 ; i < 10 ; ++i)
  std::cout << std::hex << static_cast<int>(array[i]) << '\n';
于 2012-06-19T07:03:55.523 回答
0

cout << HEX <<
不能用于 char* 来打印十六进制字符字符串,但您可以将其用于 int 、double、float 等。

而且,当你第二次打印时,为什么字符串有一些乱码是因为你没有给字符串一个 '\n' ,这意味着字符串的结尾

于 2012-06-19T07:05:18.657 回答