结构中的字符数组 - 不更新?

Char array in a struct - not renewing?

我有一个 for 循环,我每次都在堆栈上创建一个结构的新实例。该结构仅包含 2 个变量 - 2 个 64 字节的字符数组。

代码如下:

        for (std::map<std::string, std::string>::iterator iter = m_mDevices.begin(); iter != m_mDevices.end(); ++iter)
        {
            Structs::SDeviceDetails sRecord;
            if (false == GenerateDeviceCacheRecord(iter->first, iter->second, sRecord)) // could just pass iter in?
            {
                // Failed to create cache record
                return false;
            }   
        }

我在调试器中看到的真正奇怪的事情是,每次我循环时,我在 sRecord 的缓冲区中看到相同的值。即 sRecord.m_strUsername 和 sRecord.m_strPassword 得到 "written over" 而不是新创建的结构。

如果 sRecord.m_strUsername 在第一轮循环中是 "abc",那么在 GenerateDeviceCacheRecord 函数(仅修改 sRecord)之后,sRecord.m_strUsername 可能是 "HIc",其中 c是第一个循环中的角色!我显然期待 "abc" 和 "HI",而不是 "abc" 和 "HIc"。有谁知道这里会发生什么?

谢谢

额外代码:

namespace Constants
{
    static const int64 MAX_HOSTNAME_BUFFER              = 64;
    static const int64 MAX_ILA_BUFFER                   = 64;
};

    struct SDeviceRecordDetails
    {
        char        m_strHostname[Constants::MAX_HOSTNAME_BUFFER];
        char        m_strILA[Constants::MAX_ILA_BUFFER];
    };  

bool GenerateDeviceCacheRecord(std::string strHostname, std::string strILA, Structs::SDeviceRecordDetails& sRecord)
{
    // Convert strings to char arrays to store in the authentication cache manager records
    if (strHostname.length() > Constants::MAX_HOSTNAME_BUFFER)
        return false;
    if (strILA.length() > Constants::MAX_ILA_BUFFER)
        return false;

    std::copy(strHostname.begin(), strHostname.end(), sRecord.m_strHostname);
    std::copy(strILA.begin(), strILA.end(), sRecord.m_strILA);
    return true;
}

    //! @brief Devices retrieved from XML file
    std::map<std::string, std::string> m_mDevicesAuthenticated;

我在这里没有看到任何初始化。你看到的是以前在内存中那个地方发生的任何事情,今天对你来说恰好是那些数据成员的以前的内容。

所以。我很感激你试图接近一个更好的问题。所以我要和你一起采取一些后续步骤。

您发布的内容并不是真正的 mcve。

这是您的问题的解决方案:

#include <iostream>
#include <cstdint>
#include <map>
#include <string>
#include <algorithm>

namespace Constants
{
    static const int64_t MAX_HOSTNAME_BUFFER              = 64;
    static const int64_t MAX_ILA_BUFFER                   = 64;
};

struct SDeviceRecordDetails
{
    char m_strHostname[Constants::MAX_HOSTNAME_BUFFER];
    char m_strILA[Constants::MAX_ILA_BUFFER];
};  

bool GenerateDeviceCacheRecord(std::string strHostname, std::string strILA, SDeviceRecordDetails& sRecord)
{
    // Convert strings to char arrays to store in the authentication cache manager records
    if (strHostname.length() > Constants::MAX_HOSTNAME_BUFFER)
        return false;
    if (strILA.length() > Constants::MAX_ILA_BUFFER)
        return false;

    std::copy(strHostname.begin(), strHostname.end(), sRecord.m_strHostname);
    std::copy(strILA.begin(), strILA.end(), sRecord.m_strILA);
    return true;
}

std::map<std::string, std::string> m_mDevices;

int main() {
    m_mDevices["hello"] = "foo";
    m_mDevices["buzz"] = "bear";

    for (std::map<std::string, std::string>::iterator iter = m_mDevices.begin(); iter != m_mDevices.end(); ++iter) {
        SDeviceRecordDetails sRecord;
        const bool result = GenerateDeviceCacheRecord(iter->first, iter->second, sRecord);

        if (result == false)
            std::cout << "Failed\n";
        else
            std::cout << sRecord.m_strHostname << " " << sRecord.m_strILA << "\n";
    }
}

注意事项:

  1. 我可以按原样使用它(而不是你问题中的两个代码块)并将它扔给编译器。
  2. 我包含了正确的 #include 行。
  3. 您的类型名称中存在您的代码中未表示的命名空间。
  4. m_mDevicesAuthenticated != m_mDevices.
  5. 您没有包含任何实际有任何输出的内容。
  6. m_mDevices 中到底有什么?这真的很重要!
  7. 在其他小的更正中,我必须对代码应用才能构建它。

这段代码做了什么?

此代码几乎可以生成 正确的 输出。它有一个错误,因为写入 sRecord 的字符串不是空终止的。

由于编译器生成代码的方式,并且您没有明确地清除 sRecord 每个循环,这很可能是您问题的根本原因。

让我们解决这个问题:

而不是:

std::copy(strHostname.begin(), strHostname.end(), sRecord.m_strHostname);
std::copy(strILA.begin(), strILA.end(), sRecord.m_strILA);

我们来做:

snprintf(sRecord.m_strHostname, Constants::MAX_HOSTNAME_BUFFER, "%s", strHostname.c_str());
snprintf(sRecord.m_strILA, Constants::MAX_ILA_BUFFER, "%s", strILA.c_str());

或者您可能担心 sRecord 每个循环以什么开始:

在这种情况下,sRecord不会在每个循环开始时初始化。出于优化目的,编译器可以自由地在结构中包含垃圾数据。

碰巧大多数编译器会将结构的每次迭代放置在内存中完全相同的位置。这意味着结构中的垃圾数据可能是上一次迭代的数据。或者其他一些垃圾,具体取决于编译器优化的功能。

您可以通过初始化结构以包含显式数据来解决此问题:

SDeviceRecordDetails sRecord = {};

这一切看起来像什么:

修复了所有错误的完成代码如下所示:

#include <iostream>
#include <cstdint>
#include <map>
#include <string>
#include <algorithm>

namespace Constants
{
    static const int64_t MAX_HOSTNAME_BUFFER              = 64;
    static const int64_t MAX_ILA_BUFFER                   = 64;
};

struct SDeviceRecordDetails
{
    char m_strHostname[Constants::MAX_HOSTNAME_BUFFER];
    char m_strILA[Constants::MAX_ILA_BUFFER];
};  

bool GenerateDeviceCacheRecord(std::string strHostname, std::string strILA, SDeviceRecordDetails& sRecord)
{
    // Convert strings to char arrays to store in the authentication cache manager records
    if (strHostname.length() > Constants::MAX_HOSTNAME_BUFFER)
        return false;
    if (strILA.length() > Constants::MAX_ILA_BUFFER)
        return false;

    snprintf(sRecord.m_strHostname, Constants::MAX_HOSTNAME_BUFFER, "%s", strHostname.c_str());
    snprintf(sRecord.m_strILA, Constants::MAX_ILA_BUFFER, "%s", strILA.c_str());
    return true;
}

std::map<std::string, std::string> m_mDevices;

int main() {
    m_mDevices["hello"] = "foo";
    m_mDevices["buzz"] = "bear";
    m_mDevices["zed"] = "zoo";

    for (std::map<std::string, std::string>::iterator iter = m_mDevices.begin(); iter != m_mDevices.end(); ++iter) {
        SDeviceRecordDetails sRecord = {};
        const bool result = GenerateDeviceCacheRecord(iter->first, iter->second, sRecord);

        if (result == false)
            std::cout << "Failed\n";
        else
            std::cout << sRecord.m_strHostname << " " << sRecord.m_strILA << "\n";
    }
}

并输出:

buzz bear
hello foo
zed zoo

这在我看来是正确的。