char[]和int[]的区别

4

最近我看了一个视频,视频说当我定义一个整数数组时

int my_array[] = {1,2,3};

如果我打印出我的数组cout << my_array;,那么我将得到内存中第一个整数的地址,但是当我们定义一个字符数组时

char my_string[] = "Hello";

当我尝试打印my_string cout << my_string时,它返回Hello,与指向字符的指针类似

char mystring[] = "HELLO";
char *my = mystring;
cout << my << endl;//HELLO

当我们尝试打印指针变量时,它返回了字符串。

我读过这篇文章,并且知道字符串会携带它的内存地址。但我仍然无法理解为什么字符数组打印字符串字面值,而int数组打印第一个元素的地址。

先行感谢。


char *my = mystring; -> char *my = my_string;?“为什么字符数组返回字符串字面值”,你的意思是执行cout << mystring会__打印__字符串吗? - KamilCuk
sorry fixed the typo - Alex
它们都返回第一个的地址。这就是C语言中字符串的表示方式:作为指向以'\0'字符结尾的字符序列的指针。(至少在转换为指针时如此;int[]将分解为int*,但最初不同。) - Rup
@UlrichEckhardt 抱歉,我写错了,请看我的编辑。 - Alex
2
这个回答解决了你的问题吗?cout << 使用char*参数打印字符串,而不是指针值 - flowit
显示剩余2条评论
5个回答

5
为什么字符数组返回字符串字面值,而整数数组返回第一个元素的地址。
我假设“返回”一词是指“打印”。
因为非成员std::ostream::operator<<(ostream&, const char *)重载遍历char*指针所指向的内存并打印其内容,而没有std::ostream::operator<<(int*)重载,因此int*被强制转换为const void*,并使用std::ostream::operator<<(const void*)重载来打印该值,该函数打印指针的值。
您仍然可以通过手动转换来打印指向字符串的指针的值:
cout << static_cast<void*>(my_string) << endl;

谢谢,所以最终字符串被打印的唯一原因是因为i/o流重载? - Alex
是的,因为它被指定为以那种方式运作。 - KamilCuk

4
这是源自于C语言遗留下来的问题,因为标准库必须支持C风格的字符串(即以char*为结尾的字符串)。为了解决这个问题,std::cout中有一个重载函数可以接受const char*类型的输入,将其视为C风格字符串并打印出空字符(null terminator)之前的内容。
当一个指针被传递给std::cout时,打印其地址是正常的行为(这就是你得到的int指针内存地址输出的原因)。

3

my_array 将包含内存中第一个整数的地址,

不对。my_array将包含内存中的三个整数。

如果我打印cout << myarray << endl,则会打印内存中第一项的地址

是的。这就是字符流被指定如何行为的方式。插入指针时,会打印出地址。除非您插入指向char的指针,它将被 differently 处理。

那么 differently 是什么意思?

根据文档,将打印指向的字符及其兄弟,直到达到空终止符字符。


1
如果我执行cout << myarray << endl,那么它会打印内存中第一个项目的地址。 - Alex
哦,好的,谢谢。它有什么不同的处理方式吗? - Alex

1

这是一个字符数组的声明

char my_string[] = "Hello";

等价于以下声明。
char my_string[] = { 'H', 'e', 'l', 'l', 'o', '\0' };

这意味着数组的元素由字符串文字的字符初始化,包括其终止零。

在表达式中使用数组时,除了极少数情况外,它们会被转换为指向它们的第一个元素的指针。

例如,如果您正在使用sizeof运算符,则数组类型的对象不会转换为指向其第一个元素的指针。这是其中的一种罕见情况。

下面是一个演示程序:

#include <iostream>

int main() 
{
    int my_array[] = { 1, 2, 3 };
    char my_string[] = "Hello";

    std::cout << "sizeof( my_array ) = " << sizeof( my_array ) << '\n';
    std::cout << "sizeof( my_string ) = " << sizeof( my_string ) << '\n';

    return 0;
}

它的输出是:
sizeof( my_array ) = 12
sizeof( my_string ) = 6

例如,当数组类型的对象被用作运算符 * 的操作数时,它将被转换为指向其第一个元素的指针。

这里是另一个示例程序。

#include <iostream>

int main() 
{
    int my_array[] = { 1, 2, 3 };
    char my_string[] = "Hello";

    std::cout << "*my_array = " << *my_array << '\n';
    std::cout << "*my_string = " << *my_string << '\n';

    return 0;
}

该程序的输出为:
*my_array = 1
*my_string = H

在C++标准中定义了重载的operator <<,用于输出由指向char类型的指针指向的字符串(以零字符结尾的字符序列)。
因此,如果您编写
std::cout << my_string << '\n';

然后,在调用运算符<<时,字符数组会隐式转换为指向其第一个元素的指针,并输出指向的字符串。

对于整数数组,运算符<<的定义方式是仅输出该数组的地址,即其第一个元素的地址。

下面是一个演示程序。

#include <iostream>

int main() 
{
    int my_array[] = { 1, 2, 3 };
    char my_string[] = "Hello";

    std::cout << my_array << '\n';
    std::cout << my_string << '\n';

    return 0;
}

它的输出可能看起来像:

0x7ffdcfe094e4
Hello

如果您想让字符数组选择输出数组地址的重载运算符<<,则应将该数组(隐式转换为指向其第一个元素的指针)强制转换为类型void *
这里是另一个演示程序。
#include <iostream>

int main() 
{
    int my_array[] = { 1, 2, 3 };
    char my_string[] = "Hello";

    std::cout << my_array << '\n';
    std::cout << static_cast<void *>( my_string ) << '\n';

    return 0;
}

它的输出可能是:

其输出可能为

0x7ffef7ac0104
0x7ffef7ac0112

1
实际上,my_array 是一个 int[3] 数组,而 mystring 是一个 char[6] 数组。 cout << my_string; 打印字符串的原因是因为这些转换被应用了:char[6] -> char const *,并且 ostream 的 operator<< 知道如何将 char const * 视为 string
对于 cout << my_array,转换将是 int[3] -> int * -> void const *。在 void const * 上的 ostream 的 operator<< 只会打印地址。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接