C ++未初始化的局部变量

时间:2014-06-29 00:37:57

标签: c++

我有一个功能:

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);

我收到一个错误:未初始化的局部变量:对于所有三个参数。在我的脑海里,它变成了:我宣布主要,次要,构建,并且他们填补了这个功能。在调用代码的前三行中已经为它们分配了空间。

我肯定在这里遗漏了一些东西。有人可以帮我解释一下吗?

5 个答案:

答案 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的回答。