我有以下代码
NCore.h
#ifndef _NCORE_H_
#define _NCORE_H_
#include <Windows.h>
#include <cstdio>
namespace Neat
{
class NCore
{
private:
// Structure Definitions
struct NApplicationVersion
{
int major = 0;
int minor = 0;
int build = 0;
LPCSTR toString();
};
// Application Variables
LPCSTR applicationName;
NApplicationVersion applicationVersion;
protected:
public:
NCore();
LPCSTR ApplicationName(LPCSTR _applicationName = NULL);
NApplicationVersion ApplicationVersion(LPCSTR _applicationVersion = NULL);
};
}
#endif
NCore.cpp
#include "NCore.h"
Neat::NCore::NCore()
{
this->applicationName = NULL;
}
LPCSTR Neat::NCore::NApplicationVersion::toString()
{
char str[16];
memset(&str, 0, sizeof(str));
sprintf_s(str, sizeof(str), "%i.%i.%i", this->major, this->minor, this->build);
return str;
}
LPCSTR Neat::NCore::ApplicationName(LPCSTR _applicationName)
{
if (_applicationName)
this->applicationName = _applicationName;
return this->applicationName;
}
Neat::NCore::NApplicationVersion Neat::NCore::ApplicationVersion(LPCSTR _applicationVersion)
{
if (_applicationVersion)
{
//I know this isn't needed. I was just testing something.
Neat::NCore::NApplicationVersion *nav = (Neat::NCore::NApplicationVersion *)malloc(sizeof(Neat::NCore::NApplicationVersion));
sscanf_s(_applicationVersion, "%i.%i.%i", &nav->major, &nav->minor, &nav->build);
this->applicationVersion.major = nav->major;
this->applicationVersion.minor = nav->minor;
this->applicationVersion.build = nav->build;
free(nav);
}
return this->applicationVersion;
}
的main.cpp
#include <Windows.h>
#include "NCore.h"
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT iCmdShow)
{
Neat::NCore n;
n.ApplicationName("test");
LPCSTR test = n.ApplicationName();
LPCSTR test2 = n.ApplicationVersion().toString();
if (strcmp(test2, "0.0.0") == 0)
{
MessageBox(NULL, "", "", MB_OK);
}
n.ApplicationVersion("10.50.136");
if (strcmp(test2, "0.0.0") == 0)
{
MessageBox(NULL, "", "", MB_OK);
}
LPCSTR test3 = n.ApplicationVersion().toString();
if (test3 == "10.50.136")
{
MessageBox(NULL, "", "", MB_OK);
}
while (true);
return 0;
}
我的问题是test2初始化为“0.0.0”并显示第一个MessageBox。但在我调用ApplicationVersion(“10.50.136”)后,它将test2更改为“10.50.136”,并且未显示第二个MessageBox。
有人可以解释为什么会发生这种情况/如何解决?
编辑:我正在测试一个既可以作为get / set函数运行的函数。我对此很新,我通过失败来学习。我无法弄清楚到底出了什么问题。编辑2:我改变了代码如下......
NCore.h
struct NApplicationVersion
{
int major = 0;
int minor = 0;
int build = 0;
char asString[16];
LPCSTR toString();
};
NCore.cpp
LPCSTR Neat::NCore::NApplicationVersion::toString()
{
memset(this->asString, 0, 15);
sprintf_s(this->asString, 16, "%i.%i.%i", this->major, this->minor, this->build);
return this->asString;
}
这可行吗?
根据我的理解,我把变量“str”放在堆栈上。这导致它在内存中没有设置位置(?),当其他调用改变了堆栈时,它们也改变了指针“test2”试图读取的数据?
答案 0 :(得分:2)
toString
通过返回一个本地分配给函数的数组(str
)并使用return
超出范围来调用未定义的行为:
LPCSTR Neat::NCore::NApplicationVersion::toString()
{
char str[16];
memset(&str, 0, sizeof(str));
sprintf_s(str, sizeof(str), "%i.%i.%i", this->major, this->minor, this->build);
return str;
}
在大多数常见的C ++实现中,str
将在堆栈中。 (C ++标准不需要统一的“堆栈”概念,其中所有自动变量都存在,但大多数常见的实现都是这样的。)
因此,修改堆栈的后续函数也将修改调用toString()
所指向的C样式字符串。例如,对n.ApplicationVersion()
的后续调用可能会废弃str
。只要字符串更改为“0.0.0”以外的任何内容,您的第二个消息框就不会显示,并且以这种方式破坏堆栈也不会花费太多。
根据您的后续编辑:使字符串成为您的类的成员将稍微工作。对toString
的任何调用都将重写此字符串,从而影响保存指向此缓冲区的指针的所有调用方。
但是,这肯定比在堆栈上保存字符串更安全。此外,只要toString
只写入此缓冲区,就可以明确定义该字符串何时有效的规则。
答案 1 :(得分:1)
LPCSTR
不是字符串,它只是指向char数组的指针。设置新版本时,char数组本身正在发生变化。这就是你立即观察test2
变量的变化的原因。如果您希望不更改此字符串,请将其复制并保存在内部缓冲区中。