我有一个for循环,我每次都在堆栈上创建一个结构的新实例。该结构仅包含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;
最佳答案
所以。感谢您尝试接近一个更好的问题。因此,我将与您一起采取一些后续措施。
您发布的内容并不是真正的mcve。
这是您的问题的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";
}
}
注意事项:
我可以直接使用它(而不是您的问题中的两个代码块),然后将其扔给编译器。
我包括正确的
#include
行。您的类型名称中有一些名称空间未在代码中表示。
m_mDevicesAuthenticated
!= m_mDevices
。您没有包含实际上有任何输出的任何内容。
m_mDevices
中实际上是什么?这一点非常重要!在其他一些小的更正中,我不得不将其应用于代码以使其得以构建。
这段代码是做什么的?
此代码几乎可以产生正确的输出。它有一个错误,因为写入
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
在我看来,这看起来很正确。
关于c++ - 结构中的Char数组-不更新吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28461998/