我有一个功能:
VOID GetOSVersion(PDWORD major, PDWORD minor, PDWORD build)
{
OSVERSIONINFO osver;
ZeroMemory(&osver, sizeof(OSVERSIONINFO));
osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osver);
if(major)
*major = osver.dwMajorVersion;
if(minor)
*minor = osver.dwMinorVersion;
if(build)
*build = osver.dwBuildNumber;
}
我想这样调用它:
PDWORD major;
PDWORD minor;
PDWORD build;
GetOSVersion(major, minor, build);
我收到一个错误:未初始化的局部变量:对于所有三个参数。在我的脑海里,它变成了:我宣布主要,次要,构建,并且他们填补了这个功能。在调用代码的前三行中已经为它们分配了空间。
我肯定在这里遗漏了一些东西。有人可以帮我解释一下吗?
答案 0 :(得分:3)
当涉及到需要指针参数的函数时,你犯了许多错误。
当函数需要指针作为参数时,它并不意味着你盲目地声明指针并将其传递给函数。该函数要求的是address-of
现有的,有效的实体。
DWORD major, minor, build;
GetOSVersion(&major, &minor, &build);
上面的DWORD
是有效的,所做的只是将这些变量的地址传递给函数。
与此相关的另一个错误(不是错误,因为它会给出所需的结果,但仍然是“错误”)是声明一个指针,让它指向某个有效的地方,然后将其传递给功能。换句话说:
PDWORD major, minor, build;
major = new DWORD;
minor = new DWORD;
build = new DWORD;
GetOSVersion(major, minor, build);
delete major;
delete minor;
delete build;
或
PDWORD pmajor, pminor, pbuild;
DWORD major, minor, build;
pmajor = &major;
pminor = &pminor;
pbuild = &build;
GetOSVersion(pmajor, pminor, pbuild);
我看过以这种方式编写的代码。这表明当函数需要指针作为参数时,程序员并不清楚它的含义。程序员错误地认为指针必须被声明,让它指向某个有效的地方,然后传递这个指针。
是的,你得到的结果没有崩溃,但是调用分配器(new / delete)是浪费时间,或者如果没有调用分配器,则创建不必要地混淆代码的不必要的指针变量。
所以最简单的方法就是上面的第一个例子。只需声明非指针类型,然后传递地址。
答案 1 :(得分:2)
问题在于:
DWORD major;
DWORD minor;
DWORD build;
GetOSVersion(&major, &minor, &build);
修正:
VOID GetOSVersion(PDWORD major, PDWORD minor, PDWORD build)
{
OSVERSIONINFO osver = {};
osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osver);
if(major)
*major = osver.dwMajorVersion;
if(minor)
*minor = osver.dwMinorVersion;
if(build)
*build = osver.dwBuildNumber;
}
DWORD major = 0;
DWORD minor = 0;
DWORD build = 0;
GetOSVersion(&major, &minor, &build);
PDWORD是指向DWORD的指针。所有三个参数都是输出参数。在C / C ++中,它是一种常见用法:如果要从函数返回多个值,则需要将指针(或c ++情况下的引用)传递给变量:
int var = 0;
if(some_function_that_can_fail_and_write_result(&var))
;//do something
在您的情况下,您正在通过值将未初始化的指针传递给函数。它与:
相同void foo(int parameter);
// ...
int a;
foo(a);
你有很多方法:
通过引用传递未初始化的指针:
VOID GetOSVersion(PDWORD& major, PDWORD&, PDWORD&)
{
//...
major = new DWORD(osver.dwMajorVersion);
}
// usage:
PDWORD major;
GetOSVersion(major, ....);
//...
delete major;
通过引用传递所有参数:
VOID GetOSVersion(DWORD& major, DWORD&, DWORD&)
{
//...
major = osver.dwMajorVersion;
}
// usage:
DWORD major = 0;
GetOSVersion(major, ....);
使用您的GetOSVersion()版本,但在开头
中使用此答案中的修复程序答案 2 :(得分:2)
你可能想要拥有变量声明并像这样调用你的函数
DWORD major;
DWORD minor;
DWORD build;
GetOSVersion(&major, &minor, &build);
使用指针引用输出参数,因此需要将它们指向有效的内存地址。您可以使用'address-of'(&
)运算符来引用这些变量来获取有效指针,如上所示。
使用c ++,您可以通过引用参数使用,这将使事情更清晰
VOID GetOSVersion(DWORD& major, DWORD& minor, DWORD& build) {
OSVERSIONINFO osver;
ZeroMemory(&osver, sizeof(OSVERSIONINFO));
osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osver);
// Note there's no check needed if the pointers are valid!
major = osver.dwMajorVersion;
minor = osver.dwMinorVersion;
build = osver.dwBuildNumber;
}
DWORD major;
DWORD minor;
DWORD build;
GetOSVersion(major, minor, build);
无需在第一个位置使用上述任何示例调用new()
分配器(并且需要使用正确的动态内存分配管理)。
答案 3 :(得分:0)
这些都是指针。它们没有指向您分配的任何内存。它们没有在函数中“填充”,它们习惯于访问(未初始化的)内存。
答案 4 :(得分:-1)
您可能没有收到错误但是出现警告(但您可能已将编译器配置为将警告视为错误)。
如果执行,你的程序会因为你正在写入他们指向的内存而被段错误,但由于它们未初始化,它们包含无效/随机地址。
可能的解决方案
PDWORD major = new DWORD;
PDWORD minor = new DWORD;
PDWORD build = new DWORD;
假设PDWORD
被定义为*DWORD
。
不要忘记删除!
编辑:实际上将它们分配到堆栈更为明智 - 请参阅user2451677的回答。