0

考虑这段代码。

#include <iostream>
#include <vector>

using namespace std;


int main()
{
    vector <int *> test;
    vector <int *> v;
    int *a = new int;
    int *b = new int;
    *a = 1;
    *b = 2;
    v.push_back (a);
    v.push_back (b);
    for (int i = 0; i < 2; ++i)
    {
        int n = *v[i];
        test.push_back (&n);
    }
    cout << *test[0] << " " << *test[1] << endl;
    delete a;
    delete b;
    return 0;
}

问题的陈述是:

“鉴于此代码,请回答以下问题:

  1. 为什么“测试”向量只包含 2?

  2. 我们如何更改 for 循环以正确复制(只有 for 循环内的代码)?”

我无法回答这些问题中的任何一个,因此将不胜感激。

提前致谢。

4

4 回答 4

4

该代码引入了悬空指针。循环体如下所示:

{
    int n = *v[i];
    test.push_back (&n);
}

n一旦循环体结束,局部变量就会失去作用域,所以指针&n现在是一个悬空指针。如果它只test包含 2,那只是随机出现的未定义行为

如果要“正确”将数据复制到test,可以将for循环体更改为:

{
    int* n = new int;
    *n = *v[i];
    test.push_back (n);
}

请用一粒盐“正确”...

于 2013-05-16T20:53:58.400 回答
1

您将两个相同的指针推ntest数组。n等于第一个数组的最后一个元素。请注意,控制流退出循环后,所有指针都n变为无效。因此,实际上您的test数组包含无效指针,而不是指向 2s 的指针。

您应该创建每个整数的副本:

int* n = new int(*v[i]);
test.push_back (n);

另请注意,这里有内存泄漏。使用创建的每个 intnew应稍后使用 销毁delete

于 2013-05-16T20:55:44.520 回答
1

第一个问题是一个技巧问题:向量包含指向不再存在的变量的指针,并且取消引用可能会导致几乎任何输出。我想在某些机器和编译器上它会打印所有2的 s 。

我无法理解练习试图做什么(例如为什么它使用指针向量),所以我无法真正帮助解决问题。

您可以做到这一点的一种方法是test按价值存储:

首先将测试向量更改为vector <int> test;

然后将 push_back 更改为类似的内容test.push_back (n);,最后更改 print 语句以删除现在不需要的*运算符。

编辑评论:

首先,我怀疑这本书:它不应该展示未定义的行为或指向单个内置类型的原始指针。但是如果你愿意,你可以改变你的循环体:

 for (int i = 0; i < 2; ++i)
 {
     int* n = new int;
    *n = *v[i];
     test.push_back (&n);
 }

请注意,除非您稍后使用这些指针,否则这都会导致内存泄漏delete,按值存储可以消除这个问题。

于 2013-05-16T20:54:05.027 回答
0

1)我认为问题的前提是错误的。循环向 中添加了两个元素test,每个元素都包含自动变量的地址n,其范围仅限于循环体。不能保证n在两次循环中都会分配相同的内存位置,但我想大多数编译器很可能会在两次循环中重用相同的位置。

此外,n超出了输出语句的范围。所以引用指向test这些内存位置的指针是未定义的。同样,它们很有可能仍然包含循环中分配的值。

因此,只有n在第二次循环中重复使用相同的位置并且在执行输出语句时该位置没有被覆盖时,输出才会是“2 2”。不保证这些前提中的任何一个。

2) 要在不更改循环外任何内容的情况下获得输出“1 2”,可以更改nto的定义int& n = *v[i],这将是给定代码的单个字符更改,尽管最终结果相当奇怪。

一个更简单的解决方案是消除临时n和简单的test.push_back(v[i]).

于 2013-05-16T21:30:04.777 回答