考虑以下示例:

#include <iostream>
#include <sstream>
#include <vector>
#include <wchar.h>
#include <stdlib.h>

using namespace std;

struct odp {
    int f;
    wchar_t* pstr;
};

int main()
{
    vector<odp> vec;
    ostringstream ss;

    wchar_t base[5];
    wcscpy_s(base, L"1234");

    for (int i = 0; i < 4; i++)
    {
        odp foo;
        foo.f = i;

        wchar_t loopStr[1];
        foo.pstr = loopStr; // wchar_t* = wchar_t ? Why does this work?
        foo.pstr[0] = base[i];

        vec.push_back(foo);
    }

    for (vector<odp>::iterator iter = vec.begin(); iter != vec.end(); iter++)
    {
        cout << "Vec contains: " << iter->f << ", " << *(iter->pstr) << endl;
    }
}


这将产生:

Vec contains: 0, 52
Vec contains: 1, 52
Vec contains: 2, 52
Vec contains: 3, 52


我希望每次iter->fiter->pstr都会产生不同的结果。不幸的是,iter->pstr始终相同。

我怀疑每次循环时都会创建一个新的loopStr。而不是将其复制到结构中,而是仅复制一个指针。指针写入的位置将被覆盖。

如何避免这种情况?是否可以解决此问题而无需在堆上分配内存?

最佳答案

    ...
    odp foo;
    foo.f = i;

    wchar_t loopStr[1];    //A
    foo.pstr = loopStr;    //B
    foo.pstr[0] = base[i]; //C

    vec.push_back(foo);
    ...


A-您将一个数组(大小为1)分配给堆栈

B-您指定foo.pstr指向堆栈上的数组

C-您将base [i]分配给数组的第一个元素(在堆栈上)

在for循环退出其当前循环之后,变量loopStr不在范围内,并且其内容未定义。下一次循环迭代将使大多数likley重用相同的内存地址(因此,为什么在最后打印时会得到相同的值)。如果您启用了优化功能,则C编译器可能会警告您获取局部变量的地址(尽管我对此表示怀疑)。

在不使用任何堆分配的情况下,我认为您唯一的选择是在odp中固定foo.pstr的大小,即

 struct odp {
     int f;
     wchar_t pstr[1];
 };


或作为odp初始化的一部分在堆上分配数组

    ...
    odp foo;
    foo.f = i;

    foo.pstr = new wchar_t [1];
    foo.pstr[0] = base[i];

    vec.push_back(foo);
    ...


最好还是使用std :: wstring,因为您正在使用c ++,并让它为您执行内存分配和管理。

关于c++ - C++:指针,循环变量和结构麻烦,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3058006/

10-11 14:13