在 main 方法中声明与在 main 方法外部声明时的其他结果

other results when declaring in main method vs. outside from main method

我目前正在 codeforce 上做一个简单的问题。 基本上你得到一个字符串(例如“1+3+2”),你必须 return 它排序(例如“1+2+3”)。只会使用 1,2 和 3。

我开始于:

#include <iostream>
using namespace std;    

int main()
{
    string str;
    int arr[4];
    cin >>str;    

    for(int i = 0; i < str.length();i+=2)
        arr[str[i] - '0']++;    
}

我的想法是将每次出现的数字存储在一个数组中。但是如果我添加

我注意到一个问题
cout<< arr[2];

输入“1+2+3”,输出:

33

不过应该是1,因为3只出现过一次

我通过移动“string str;”解决了这个问题和“int arr[4]”,在 main:

#include <iostream>
using namespace std;

string str;
int arr[4];

int main()
{   
    cin >>str;

    for(int i = 0; i < str.length();i+=2)
        arr[str[i] - '0']++;
    cout<< arr[2];
}

输出:

1

为什么它现在可以工作了?

您没有在第一个示例中初始化 int arr[4];因此您的程序的行为是未定义的。

如果您在没有第一个 for 循环的情况下打印 arr 的内容:

for (auto x: arr) {
  std::cout << x << "\n";
}

您得到的垃圾数据恰好位于 arr 的地址:

121
32584
615125669
22063

但你不能保证得到任何东西。如果您向编译器提供无效程序,它可以为所欲为。


您可以通过初始化数组来解决这个问题:

int arr[4] = {};

这将值初始化数组,对于int意味着用0初始化。

没有初始化器的自动存储持续时间:应用默认初始化:基本 non-class 类型的数组将保留未初始化的值

在您的第一个示例中,arr 具有自动存储持续时间并且未初始化,这是默认初始化的结果:

int main() {
    // default initialization
    int arr[4];

    // reading from arr at this point (remains
    // uninitialized) is undefined behaviour.
}

数组类型默认初始化的效果是数组的每个元素都是default-initialized。默认初始化对基本 non-class 类型没有任何影响:元素将保持未初始化状态。从这些元素中读取(在您的示例中对元素调用 operator++)是未定义的行为。

你可以,例如value-initialize arr 使用以下语法:

int main() {
    int arr[4]{};
}

数组的每个元素都是 value-initialized,这反过来又会导致数组(基本 non-class 类型)的每个元素都是 zero-initialized。


静态存储期限:zero-initialization 适用

第二个例子中,arr不再是自动存储时长,而是静态存储时长,静态初始化的规则适用,会导致arr为zero-initialized。

默认情况下,C++ 不会将数组初始化为 0。你的初始内容是不可预测的,你的结果也是如此。

有多种方法可以解决该问题。我建议使用 std::vector,像这样声明变量:

#include <vector>
std::vector<int> arr(4, 0); 

第一个参数是大小,第二个是所有元素的初始值(默认为0)。您可以将它用作带 [] 的数组。它还有其他有用的功能,例如可以根据需要进行扩展。

或者,您也可以使用memset来清除数组:

#include <cstring>
memset(arr, 0, sizeof(arr));

此功能较旧,您需要更加小心。