c++ - 使用函数调整动态结构数组的大小

标签 c++ struct dynamic-arrays

据我所读,我的代码应该没有问题。 我正在阅读 Alex Allain 的 jumping into C++,他像这样复制动态 int 数组,但是当我尝试以相同的方式复制结构数组时,它给了我这个错误:

Unhandled exception at 0x777108B2 in Friend Tracker.exe: Microsoft C++ exception: std::length_error at memory location 0x006FF838.

根据我的理解,这告诉我堆数据用完了。但是我有 14GB 的未使用 RAM,这怎么可能?

在看别人同样错误的问题时,他们正在保存多个大小为1GB的数组拷贝。

这让我认为问题出在我内存中的位置,但为什么编译器没有在我的新数组中分配正确数量的堆数据?

struct frnd
{
    string firstName;
    string lastName;
    int lastTalked;
};

int main()
{
    int size = 1;
    frnd* friendsList;

    friendsList = new frnd[2];
    friendsList[1].firstName = "larry";
    frnd* temp;
    temp = new frnd[4];

    for (int i = 1; i < 3; i++)
    {
        temp[i] = friendsList[i];
    }

    delete[] friendsList;

    friendsList = new frnd[4];
    for (int i = 1; i < size; i++)
    {
        friendsList[i] = temp[i];
    }

    delete[] temp;

    cout << "\n\n" << friendsList[1].firstName << "\n\n";
    system("PAUSE");
    return 0;
}

最佳答案

你的错误是由于 C++ 中的数组索引是从零开始的,但你使用它就像数组是从一开始的。

for (int i = 1; i < 3; i++) {
    temp[i] = friendsList[i];
}

friendsList指向二元素数组中的第一个元素。这会访问 friendsList[1] , 这没关系。 (但请注意,它是数组中的第二个元素,而不是第一个。)

在下一次迭代中它访问 friendsList[2] ,这将是数组的 third 元素,但您的数组只有两个元素。因此,这是越界数组访问,它会导致未定义的行为。在您的情况下,这表现为以下事件序列的异常:

  • 您的代码试图复制 friendsList[2]对象(frnd),但这超出了数组分配的末尾。 这是未定义的行为,不好,句号。但是,为了解释为什么你得到这个特定的异常...
  • 正在复制 frnd对象使用默认的复制构造函数,它只是将源对象的每个数据成员复制到目标。
  • 当编译器试图复制 friendsList[2].firstName ,您有效地使用了 与您的分配相邻的一些其他内存 作为 std::string对象,当在该内存区域中没有构造此类对象时。
  • std::string复制赋值运算符尝试读取字符串内部数据成员并获取垃圾(未初始化和/或不确定的值,这里的区别是没有意义的,因为我们已经进入了 UB 领域)。它可能尝试做的第一件事是分配一个 char数组使用来自不存在的源字符串对象的垃圾“字符串长度”值,如果 that 成功,那么它将尝试从未初始化指针指向的内存区域复制那么多字符。从这种“复制我的垃圾数据,就好像它是一个 string 对象”操作而没有某种异常的可能性非常非常低。
    • 另一个可能的结果:&friendsList[2]可能指向尚未映射到进程地址空间的内存区域,从而在您尝试从中读取时触发访问冲突。 这实际上比调用 UB 时可能发生的其他事情更可取。

您可以通过调整循环边界来解决此问题:(int i = 0; i < 2; i++)

另一方面,你的第二个循环什么都不做,因为 isize是 1,所以测试 i < size失败。


正如在对您的问题的评论中指出的,您也没有初始化 lastTalked在您尝试复制对象之前,先将其添加到您的对象中。除了一些异常(exception),reading an uninitialized value causes undefined behavior .因此,从技术上讲,第一次循环迭代时 i is 1 也会调用未定义的行为,但对于您的特定编译器和体系结构,这可能表现为不确定值的拷贝。

这可以通过添加默认值 frnd 来解决。初始化成员的构造函数:

struct frnd
{
    frnd() : lastTalked(0) { }

    string firstName;
    string lastName;
    int lastTalked;
};

关于您的代码的其他想法:

  • 我知道这段代码是一个练习。但是,对于生产代码,我需要推荐使用 std::vector 相反。
  • using namespace std;bad practice .

关于c++ - 使用函数调整动态结构数组的大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48047508/

相关文章:

c++ - Opengl superbible example compliation errors 源代码 : drawing a triangle

c++ - IOCP WSARecv 总是返回错误 10022

c# - 在 C# 中将结构指针作为参数传递

c - "Dereferencing pointer to incomplete type", typedefs 没问题

ios - 无法将结构附加到数组属性

c++ - 使用复制构造函数 C++ 时出现段错误

c++ - 如何从方法返回动态指针数组

无法确定分配内存的正确算法

c++ - 使用模板实现 "visitor pattern"

c++ - std::string 构造函数抛出 std::out_of_range 异常