未设置的C指针不为空

Mar*_*k C 2 c null pointers variable-assignment

我正在搞乱C指针.当我编译并运行以下代码时.

例1:

#include <stdio.h>

int main()
{
    int k;
    int *ptr;
    k = 555;
    if (ptr == NULL) {
        printf("ptr is NULL\n");
    } else {
        printf("ptr is not NULL\n");
        printf("ptr value is %d\n", *ptr);
    }
    printf("ptr address is %p\n", ptr);
}
Run Code Online (Sandbox Code Playgroud)

我得到输出:

ptr is not NULL
ptr value is 1
ptr address is 0x7fff801ace30
Run Code Online (Sandbox Code Playgroud)

如果我没有为k赋值:

例2:

#include <stdio.h>

int main()
{
    int k;
    int *ptr;
    if (ptr == NULL) {
        printf("ptr is NULL\n");
    } else {
        printf("ptr is not NULL\n");
        printf("ptr value is %d\n", *ptr);
    }
    printf("ptr address is %p\n", ptr);
}
Run Code Online (Sandbox Code Playgroud)

然后输出就像我期望的那样:

ptr is NULL
ptr address is (nil)
Run Code Online (Sandbox Code Playgroud)

同样,如果我在函数外定义变量:

例3:

#include <stdio.h>

int k;
int *ptr;

int main()
{
    k = 555;
    if (ptr == NULL) {
        printf("ptr is NULL\n");
    } else {
        printf("ptr is not NULL\n");
        printf("ptr value is %d\n", *ptr);
    }
    printf("ptr address is %p\n", ptr);
}
Run Code Online (Sandbox Code Playgroud)

输出:

ptr is NULL
ptr address is (nil)
Run Code Online (Sandbox Code Playgroud)

在第一个例子中,ptr有一个地址和值,这是预期的行为吗?如果是这样的话:

  • 为什么ptr有地址和价值?
  • 这些来自哪里,是什么设置的呢?
  • 如何在本地范围内正确定义空指针并将其保持为空,直到我准备好使用它为止?

我在x64上使用Uccntu 12.04.04上的gcc进行编译:

root@dev:~# gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.3-1ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
Run Code Online (Sandbox Code Playgroud)

编辑

为了清楚起见,我已将上面的例子编号.

基于Dietrich的回答,我做了一些搜索,发现了这个问题:为什么全局变量总是初始化为'0',而不是局部变量?.

Die*_*Epp 6

C中的局部变量不会自动初始化,只会自动初始化全局变量.

int x; // 0 by default
static int y; // 0 by default

void function()
{
    static int z; // 0 by default
    int w; // Not initialized!  Could be anything!
}
Run Code Online (Sandbox Code Playgroud)

未初始化变量的值未指定.在实践中,这可能意味着不同的事情.

  • 如果您的编译器或运行时在使用之前将内存清零,则它可能为零.

  • 它可以填充像哨兵0xdeadbeef0xeeeeeeee.

  • 它可能包含来自该特定内存位置中最后一个的垃圾.(这种方法最常见.)

您正在使用GCC,它使用第三种方法,因此您看到最后一个函数使用该内存位置的垃圾.您可以使用Valgrind运行该程序(强烈推荐),它可能会使用未初始化的内存吐出错误消息,但不能保证捕获所有错误.

正确的做事方式

一种选择是如果要使用它们,则显式初始化局部变量.

void function()
{
    int *ptr = NULL;
    ...
}
Run Code Online (Sandbox Code Playgroud)

如果没有使用该值,我更喜欢保留未初始化的变量,因为编译器和Valgrind可以给我诊断消息,让我知道我对代码的理解是不正确的,如果事实证明使用了未初始化的内存.