【问题标题】:C++ pointers not accessing correct memory address, instead accessing random memory locationsC++ 指针未访问正确的内存地址,而是访问随机内存位置
【发布时间】:2021-10-16 18:54:32
【问题描述】:

我正在学习 C++,我想知道是否有人可以解释我看到的一些奇怪行为。

我目前正在学习内存管理,并且一直在使用以下代码:

#include <iostream>
#include <vector>
#include <cmath>

using namespace std;

// pass back by pointer (old C++)
const int array_size = 1e6; // determines size of the random number array

vector<int> *RandomNumbers1()
{
    vector<int> *random_numbers = new vector<int>[array_size]; // allocate memory on the heap...
    for (int i = 0; i < array_size; i++)
    {
        int b = rand();
        (*random_numbers).push_back(b); // ...and fill it with random numbers
    }
    return random_numbers; // return pointer to heap memory
}

int main (){
    vector<int> *random_numbers = RandomNumbers1();
    for (int i = 0; i < (*random_numbers).size(); i++){
        cout << (*random_numbers)[i] + "\n";     
    }
    delete random_numbers;
}

我要做的是通过调用RandomNumbers1() 函数获取指向包含随机整数的向量的指针,然后在新行上打印每个随机数。

但是,当我运行上述代码时,我得到的不是随机数,而是各种随机信息。似乎代码正在访问内存中的随机位置并打印出内容。

现在我知道我在这里做了一些愚蠢的事情——我有一个int,我正在向它添加字符串"\n"。如果我将main() 中的代码更改为以下内容,则可以正常工作:

int main (){
    vector<int> *random_numbers = RandomNumbers1();
    for (int i = 0; i < (*random_numbers).size(); i++){
        cout << to_string((*random_numbers)[i]) + "\n";   
    }
} 

但是,我无法理解使用“错误”代码的行为 - 即如何将字符串 "\n" 添加到 (*random_numbers)[i] 导致程序访问内存的随机区域,而不是我的指针指向的位置。当然,在“添加”"\n" 之前,我已经取消引用了指针并访问了位置i 的元素?那么程序是如何访问完全不同的内存地址的呢?

【问题讨论】:

  • 提示:您可以使用 -&gt; 取消引用指针,而不是使用 (*ptr).func()。只需写:ptr-&gt;func()
  • new vector&lt;int&gt;[array_size]; 创建一个向量数组,但您可能根本不想动态分配一个向量...
  • 不相关,但您的意思是只使用您分配的vectors 之一吗?除了一个之外,所有的都是空的。另外,您需要使用delete[],因为您使用了new[]

标签: c++ pointers memory-management


【解决方案1】:

"\n" 是一个字符串文字。它是一个数组,它被转换为指向表达式中第一个元素的指针。

(*random_numbers)[i] 是一个整数。

将指针添加到整数意味着将指针前进整数。

这将导致指针超出范围,因为 "\n" 只有 2 个元素('\n''\0'),但从 rand() 函数返回的数字可能大于 2。

【讨论】:

    【解决方案2】:

    您的代码有几个问题。

    • 您正在使用delete 而不是delete[] 来释放使用new[] 分配的数组。

    • 您正在创建一个包含 1000000 个 vectors 的数组,但仅使用 1000000 个整数填充第一个 vector。您可能只想创建 1 个vector

    • 当通过指针访问对象的成员时,您可以并且应该使用-&gt; 运算符。使用 *. 运算符也可以,但更冗长且更难阅读/编码。

    • 您尝试在每个数字后打印"\n",但您使用的是+ 运算符,而您应该使用&lt;&lt; 运算符。您不能将字符串文字附加到整数(好吧,您可以,但它会调用 指针算术,因此结果不会是您想要的,正如您所见)。

    话虽如此,请尝试更多类似的东西:

    #include <iostream>
    #include <vector>
    #include <cmath>
    using namespace std;
    
    const int array_size = 1e6; // determines size of the random number array
    
    vector<int>* RandomNumbers1()
    {
        vector<int> *random_numbers = new vector<int>;
        random_numbers->reserve(array_size);
    
        for (int i = 0; i < array_size; ++i)
        {
            int b = rand();
            random_numbers->push_back(b);
        }
    
        return random_numbers;
    }
    
    int main (){
        vector<int> *random_numbers = RandomNumbers1();
    
        for (size_t i = 0; i < random_numbers->size(); ++i){
            cout << (*random_numbers)[i] << "\n";
        }
    
        /* alternatively:
        for (int number : *random_numbers){
            cout << number << "\n";
        }
        */
    
        delete[] random_numbers;
    }
    

    但是,如果你要返回一个指向动态内存的指针,你真的应该把它包装在一个智能指针中,比如std::unique_ptrstd::shared_ptr,让它为你处理delete

    #include <iostream>
    #include <vector>
    #include <cmath>
    #include <memory>
    using namespace std;
    
    const int array_size = 1e6; // determines size of the random number array
    
    unique_ptr<vector<int>> RandomNumbers1()
    {
        auto random_numbers = make_unique<vector<int>>();
        // or: unique_ptr<vector<int>> random_numbers(new vector<int>);
    
        random_numbers->reserve(array_size);
    
        for (int i = 0; i < array_size; ++i)
        {
            int b = rand();
            random_numbers->push_back(b);
        }
    
        return random_numbers;
    }
    
    int main (){
        auto random_numbers = RandomNumbers1();
    
        for (size_t i = 0; i < random_numbers->size(); ++i){
            cout << (*random_numbers)[i] << "\n";
        }
    
        /* alternatively:
        for (int number : *random_numbers){
            cout << number << "\n";
        }
        */
    }
    

    不过,在这种情况下,根本没有充分的理由动态创建vector。 99% 的情况下,使用这样的标准容器是不必要的。由于vector 在内部管理动态内存,因此vector 本身没有理由也在动态内存中创建。而是按值返回vector,让编译器为您优化返回。

    #include <iostream>
    #include <vector>
    #include <cmath>
    using namespace std;
    
    const int array_size = 1e6; // determines size of the random number array
    
    vector<int> RandomNumbers1()
    {
        vector<int> random_numbers;
        random_numbers.reserve(array_size);
    
        for (int i = 0; i < array_size; ++i)
        {
            int b = rand();
            random_numbers.push_back(b);
        }
    
        return random_numbers;
    }
    
    int main (){
        vector<int> random_numbers = RandomNumbers1();
    
        for (size_t i = 0; i < random_numbers.size(); ++i){
            cout << random_numbers[i] << "\n";
        }
    
        /* alternatively:
        for (int number : random_numbers){
            cout << number << "\n";
        }
        */
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-01
      • 2020-02-07
      • 1970-01-01
      • 1970-01-01
      • 2020-06-24
      • 1970-01-01
      相关资源
      最近更新 更多