简体   繁体   English

为什么c++中字符arrays和integer arrays的基本属性有区别?

[英]Why is there difference between the basic properties of character arrays and integer arrays in c++?

If I execute this code:如果我执行这段代码:

#include<iostream>
using namespace std;

int main(){
    char str[20] = {'a','b','c','d','e'};
    cout<<str<<endl;
    return 0;
}

It outputs abcde but If I execute this code:它输出abcde但如果我执行此代码:

#include<iostream>
using namespace std;

int main(){
    int arr[20] = {1,2,3,4,5};
    cout<<arr<<endl;
    return 0;
}

It outputs 0x7fff22eecc30 I have tried executing this code in two different online compilers and they are giving same outputs.它输出0x7fff22eecc30我试过在两个不同的在线编译器中执行这段代码,它们给出了相同的输出。

In char array it is returning the array contents but in int array it's returning memory address.char array中,它返回数组内容,但在int array中,它返回 memory 地址。 Why is that?这是为什么? Also, how can two different online compilers return the same memory address?另外,两个不同的在线编译器如何返回相同的 memory 地址?

I have tried looking out online for this but I'm not sure what to look for?我曾尝试在网上查找此内容,但不确定要查找什么?

With char str[20] = {'a','b','c','d','e'};使用char str[20] = {'a','b','c','d','e'}; , the remaining 15 elements of the array are all set to 0. The special ostream overload for << that's used as a result of the array str decaying to a char* pointer to the first element of that array will output the array as if it's a C-style string, since the first 0 will act as a NUL terminator. ,数组的其余 15 个元素都设置为 0。 <<的特殊ostream重载用作数组str衰减为指向该数组第一个元素的char*指针的结果将 output 数组就好像它是一个 C 风格的字符串,因为第一个 0 将充当 NUL 终止符。

An equivalent way of writing the above is char str[20] = "abcde" .一种等效的写法是char str[20] = "abcde"

In your second case, the overloaded << for ostream for a const void* pointer is used (due again to pointer decay), which prints the address of the first element of the array.在第二种情况下,使用了const void*指针的重载<< for ostream (再次由于指针衰减),它打印数组第一个元素的地址。

What std::cout knows how to print std::cout知道如何打印

Under the hood cout is an object derived from the basic_ostream class template.在引擎盖下cout是从basic_ostream class 模板派生的 object。 The standard library provides some functions that tell basic_ostream how to print different types of data.标准库提供了一些函数告诉basic_ostream如何打印不同类型的数据。 (Some are member functions, some aren't - but that's not important here.) (有些是成员函数,有些不是——但这在这里并不重要。)

Here are some examples:这里有些例子:

basic_ostream<charT,traits>& operator<<(bool n);
basic_ostream<charT,traits>& operator<<(short n);
basic_ostream<charT,traits>& operator<<(int n);
basic_ostream<charT,traits>& operator<<(double f);
... and more ...

These functions tell cout (and other basic output streams) how to print bools, shorts, ints, etc.这些函数告诉cout (和其他基本的 output 流)如何打印 bools、shorts、ints 等。

There's also these two还有这两个

basic_ostream<charT,traits>& operator<<(const void* p);

template<class traits>
    basic_ostream<char,traits>& 
    operator<<(basic_ostream<char,traits>&, const char*);

The first one tells cout how to print the address of an untyped pointer (a void* ).第一个告诉cout如何打印无类型指针(a void* )的地址。

The second one is intended to print C-style strings --- especially literal strings in your source code.第二个用于打印 C 风格的字符串——尤其是源代码中的文字字符串。 For example, cout << "Hello";例如, cout << "Hello";

What about arrays? arrays 呢?

The standard library doesn't provide any direct support for printing arrays (or any other collection) .标准库不为打印 arrays(或任何其他集合)提供任何直接支持 If you want to print a collection, you have to decide what format you want for that collection, and code it up yourself.如果你想打印一个集合,你必须决定你想要那个集合的格式,然后自己编码。

This is the same for structs and classes.这对于结构和类来说是一样的。 If you define your own class, cout doesn't know how to print it --- you must code that up yourself.如果您定义自己的 class, cout不知道如何打印它——您必须自己编写代码。

Why does your first example output "abcde"?为什么你的第一个例子 output “abcde”?

You're trying to print a char[20] (an array of char).您正在尝试打印一个char[20] (一个 char 数组)。 basic_ostream doesn't have an overloaded << function for arrays, so it doesn't know how to print them. basic_ostream没有为 arrays 重载 << function,所以它不知道如何打印它们。

BUT - C++ is allowed to implicitly cast an "array of T" to a "pointer to T", so your str variable is implicitly cast from char[20] to char* .但是 - C++ 被允许将“T 数组”隐式转换为“指向 T 的指针”,因此您的str变量从char[20]隐式转换为char* That matches the last overload I listed above - the one that is supposed to be used for C-style strings .这与我在上面列出的最后一个重载相匹配——应该用于 C 样式字符串的重载。 (Other answers have already discussed issues regarding the terminating zero that C-strings are supposed to have.) (其他答案已经讨论了有关 C 字符串应该具有的终止零的问题。)

What about the second example?第二个例子呢?

The type of arr is int[20] . arr的类型是int[20] Once again, cout doesn't know how to print arrays.再一次, cout不知道如何打印 arrays。

SO - C++ tries implicitly casting your int[20] to an int* . SO - C++ 尝试将您的int[20]隐式转换为int* But there is no overload for int* , so C++ tries again.但是int*没有过载,所以 C++ 再试一次。 It implicitly casts the int* to a void* (which it is allowed to do) - and now it finds a match.它隐式地将int*转换为void* (允许这样做)——现在它找到了一个匹配项。

The void* overload prints the memory address of the pointer. void*重载打印指针的 memory 地址。

This happens with all arrays except arrays of char , signed char and unsigned char .除了 arrays 的charsigned charunsigned char之外,所有 arrays 都会发生这种情况。 The array of T is cast down to a pointer to T, which is cast down to a void pointer. T 的数组向下转换为指向 T 的指针,T 向下转换为空指针。

Why is char* treated differently than any other pointer type为什么char*的处理方式不同于任何其他指针类型

Because we print C-style strings (especially string literals) a lot.因为我们经常打印 C 风格的字符串(尤其是字符串文字)。 Like, a lot a lot.喜欢,很多很多。

The most often usage of character arrays is the usage them as containers of strings.字符 arrays 最常用的用法是将它们用作字符串容器。 It is very easy to determine the size of a string due to its sentinel value that is the terminating zero character.由于其标记值是终止零字符,因此很容易确定字符串的大小。

So if in a C program you will write for example因此,如果在 C 程序中,您将编写例如

char str[20] = {'a','b','c','d','e'};
printf( "%s", str );

then the call of printf easy outputs the string "abcde" because it is well-knowb where to stop outputting characters of the character array.然后printf的调用很容易输出字符串"abcde" ,因为它是众所周知的停止输出字符数组字符的位置。

If in a similar call of printf you will specify an integer array then it is unknown what is the size of the integer array.如果在 printf 的类似调用中,您将指定一个 integer 数组,那么不知道 integer 数组的大小是多少。 How many integers stored in the array to output? output 数组中存储了多少个整数?

So a call of printf for character arrays containing strings is well-defined.因此,对包含字符串的字符 arrays 调用 printf 是明确定义的。 However if you are using a pointer of the type int * when it is unclear whether the pointer points to a single integer or a sequence of integers.但是,如果您使用的是int *类型的指针,则不清楚指针是指向单个 integer 还是指向整数序列。 And if the pointer points to a sequence of integers then what is the length of the sequence?如果指针指向一个整数序列,那么这个序列的长度是多少?

This approach was carried over to the implementation of the overloaded operator << for character arrays in C++.这种方法被用于 C++ 中字符 arrays 的重载运算符 << 的实现。

Pay attention to that if a character array does not contain a string this such a statement注意,如果字符数组不包含字符串,则有这样一条语句

std::cout << str;

results in undefined behavior.导致未定义的行为。 In this case you should use for example the following call在这种情况下,您应该使用例如以下调用

std::cout.write( str, sizeof( str ) );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM