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

时间:2015-02-11 18:43:02

标签: c++ arrays struct char

我有一个for循环,每次都在堆栈上创建一个新的struct结构。这个结构只包含2个变量 - 2个64字节的char数组。

代码如下:

        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正在“被覆盖”,而不是新创建的结构。

如果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;

2 个答案:

答案 0 :(得分:2)

因此。我很欣赏你试图接近一个更好的问题。所以我要跟你一起做下一步。

你发布的内容并非如此。

以下是您的问题:

#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. 在其他小修正中,我必须应用于代码才能构建它。
  8. 这段代码做了什么?

    此代码几乎产生正确的输出。它有一个错误,因为写入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
    

    对我来说看起来是正确的。

答案 1 :(得分:0)

我在这里看不到任何初始化。你之前在内存中看到发生的事情,今天对你来说恰好是这些数据成员的先前内容。