结构中的字符数组-不续订

Char array in a struct - not renewing?

本文关键字:数组 字符 结构      更新时间:2023-10-16

我有一个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被"重写",而不是新创建的结构。

如果在第一轮循环中,sRecord.m_strUsername是"abc",那么在GenerateDeviceCacheRecord函数(它只是修改sRecord)之后,sRecord.ms_strUsername可能是"HIc",其中c是第一次循环中的字符!很明显,我期待的是"abc"answers"HI",而不是"abc"answers"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 << "Failedn";
        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的字符串不是以null结尾的。

由于编译器是如何生成代码的,并且您没有明确地清除每个循环的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 << "Failedn";
        else
            std::cout << sRecord.m_strHostname << " " << sRecord.m_strILA << "n";
    }
}

输出:

buzz bear
hello foo
zed zoo

这在我看来是正确的。

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