【问题标题】:An unset C pointer is not null未设置的 C 指针不为空
【发布时间】:2016-05-18 18:21:08
【问题描述】:

我在搞乱 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);
}

我得到了输出:

ptr is not NULL
ptr value is 1
ptr address is 0x7fff801ace30

如果我不给 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);
}

那么输出如我所料:

ptr is NULL
ptr address is (nil)

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

示例 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);
}

输出:

ptr is NULL
ptr address is (nil)

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

  • 为什么 ptr 有地址和值?
  • 这些来自哪里,是什么原因造成的?
  • 如何在本地范围内正确定义空指针并保持它们为空,直到我准备好使用?

我在 x64 上的 Ubuntu 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)

编辑

为清楚起见,我在上面的示例中进行了编号。

根据 Dietrich 的回答,我进行了一些搜索,发现了这个问题:Why are global variables always initialized to '0', but not local variables?

【问题讨论】:

    标签: c pointers null variable-assignment


    【解决方案1】:

    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!
    }
    

    未初始化变量的值是未指定。在实践中,这可能意味着不同的东西。

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

    • 它可以用0xdeadbeef0xeeeeeeee 之类的标记来填充。

    • 它可能包含来自该特定内存位置最后的垃圾。 (这种方式最为常见。)

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

    正确的做事方式

    如果要使用局部变量,一个选项是显式初始化它们。

    void function()
    {
        int *ptr = NULL;
        ...
    }
    

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

    【讨论】:

    • 谢谢,这是有道理的,将来会这样做。在示例 2 中,指针为 NULL,尽管按权利应该是垃圾。我猜这归结为一些没有设置值的 gcc 优化?您对幕后发生的事情有任何见解吗?
    • @MarkC:只是因为它是垃圾并不意味着它不能是NULL。有时,垃圾是NULL,巧合。
    • Valgrind 不太擅长捕捉局部变量的非法使用,部分原因是在二进制级别有时无法做到这一点,部分原因是如果一个人做得不好,那么做起来就没有动力它根本没有。对于问题范围的程序,也可以使用 Frama-C 的值分析,捕获包括p = &amp;b; for (;;) { int a; *p = 1; p = &amp;a; }在内的局部变量的所有非法使用。
    【解决方案2】:

    切勿将间接运算符应用于未初始化的指针变量。如果未初始化,则尝试使用它会调用未定义的行为
    上述两个代码正在调用未定义的行为。在这种情况下,结果可能是预期的或意外的。

    最后一个代码工作正常,因为全局变量被隐式初始化为0。因此指针 ptr 被初始化为 NULL 并且你得到了正确的输出。

    【讨论】:

      【解决方案3】:

      也许你可以试试这个代码来知道你想知道什么:

      #include <stdio.h>
      #include <stdlib.h>
      typedef struct _appl{
      //the pointer
      int *ptr_int;
          float *ptr_float;
          double *ptr_double;
          char *ptr_char;
      
          //the basic data types
          int a_int;
          float a_float;
          double a_double;
          char a_char;
      
          struct _appl *next;
          } appl;
      
          //the pointers
          int *ptr_int_global;
          float *ptr_float_global;
          double *ptr_double_global;
          char *ptr_char_global;
      
          //the basic data types
          int a_int_global;
          float a_float_global;
          double a_double_global;
          char a_char_global;
      
          //pointer to structure data type
          appl *ptr_struct_global;
      
          //struct data type;
          appl a_struct_global;
      
          int main()
          {
          //the pointers
          int *ptr_int_local;
          float *ptr_float_local;
          double *ptr_double_local;
          char *ptr_char_local;
      
          //the basic data types
          int a_int_local;
          float a_float_local;
          double a_double_local;
          char a_char_local;
      
          //pointer to structure data type
          appl *ptr_struct_local;
      
          //struct data type;
          appl a_struct_local;
      
          //test the basic data types (local variables)
          puts("********");
          puts("****first test : test the basic data types (local variables)");
          puts("********");
          printf("the value of a non-initialized int is : %d\n", a_int_local);
          printf("the value of a non-initialized float is : %f\n", a_float_local);
          printf("the value of a non-initialized double is : %f\n", a_double_local);
          printf("the value of a non-initialized char is : %d\n\n", a_char_local);
      
          //test the basic data types (global variables)
          puts("second test : test the basic data types (global variables)");
          printf("the value of a non-initialized int is : %d\n", a_int_global);
          printf("the value of a non-initialized float is : %f\n", a_float_global);
          printf("the value of a non-initialized double is : %f\n", a_double_global);
          printf("the value of a non-initialized char is : %d\n\n", a_char_global);
      
          //test the pointers (local variables)
          puts("third test : test basic data type pointers (local variables)");
          if(ptr_int_local == NULL) printf("a non-initialized int pointer is NULL\n");
          else printf("a non-initialized int pointer is not NULL\n");
          if(ptr_float_local == NULL) printf("a non-initialized float pointer is NULL\n");
          else printf("a non-initialized float pointer is not NULL\n");
          if(ptr_double_local == NULL) printf("a non-initialized double pointer is NULL\n");
          else printf("a non-initialized double pointer is not NULL\n");
          if(ptr_char_local == NULL) printf("a non-initialized char pointer is NULL\n\n");
          else printf("a non-initialized char pointer is not NULL\n\n");
          puts("attention ! sometimes a non-initialized char pointer (global variables) is NULL, while sometimes not !");
      
      
          //test the pointers (global variables)
          puts("fourth test : test basic data type pointers (global variables)");
          if(ptr_int_global == NULL) printf("a non-initialized int pointer is NULL\n");
          else printf("a non-initialized int pointer is not NULL\n");
          if(ptr_float_global == NULL) printf("a non-initialized float pointer is NULL\n");
          else printf("a non-initialized float pointer is not NULL\n");
          if(ptr_double_global == NULL) printf("a non-initialized double pointer is NULL\n");
          else printf("a non-initialized double pointer is not NULL\n");
          if(ptr_char_global == NULL) printf("a non-initialized char pointer is NULL\n\n");
          else printf("a non-initialized char pointer is not NULL\n\n");
      
          //test data structure (local variable)
          puts("fifth test : test data structure type (local variables)");
          if(ptr_struct_local == NULL) printf("a non-initialized data structure pointer is NULL\n\n");
          else printf("a non-initialized data structure pointer is not NULL\n\n");
      
          //test data structure (global variable)
          puts("sixth test : test data structure type (global variables)");
          if(ptr_struct_global == NULL) printf("a non-initialized data structure pointer is NULL\n\n");
          else printf("a non-initialized data structure pointer is not NULL\n\n");
      
          ptr_struct_local = (struct _appl*)malloc(sizeof(struct _appl*));
          if(ptr_struct_local == NULL) printf("failed to allocate memory\n\n");
          else printf("success of allocating memory\n\n");
      
          appl *a = ptr_struct_local;
          //test the basic data types (in a local data structure variable)
          puts("\nseventh test : test the basic data types (in a local data structure variable)");
          printf("the value of a non-initialized int is : %d\n", a->a_int);
          printf("the value of a non-initialized float is : %f\n", a->a_float);
          printf("the value of a non-initialized double is : %f\n", a->a_double);
          printf("the value of a non-initialized char is : %d\n\n", a->a_char);
      
          //test the pointers (in a local data structure variable)
          puts("eigth test : test the pointers (in a local data structure variable)");
          if(a->ptr_int == NULL) printf("a non-initialized int pointer is NULL\n");
          else printf("a non-initialized int pointer is not NULL\n");
          if(a->ptr_float == NULL) printf("a non-initialized float pointer is NULL\n");
          else printf("a non-initialized float pointer is not NULL\n");
          if(a->ptr_double == NULL) printf("a non-initialized double pointer is NULL\n");
          else printf("a non-initialized double pointer is not NULL\n");
          if(a->ptr_char == NULL) printf("a non-initialized char pointer is NULL\n\n");
          else printf("a non-initialized char pointer is not NULL\n\n");
      
          ptr_struct_global = (struct _appl*)malloc(sizeof(struct _appl*));
          if(ptr_struct_global == NULL) printf("failed to allocate memory\n\n");
          else printf("success of allocating memory\n\n");
      
          appl *b = ptr_struct_global;
          //test the basic data types (in a global data structure)
          puts("\nninth test : test the basic data types (in a global data structure)");
          printf("the value of a non-initialized int is : %d\n", b->a_int);
          printf("the value of a non-initialized float is : %f\n", b->a_float);
          printf("the value of a non-initialized double is : %f\n", b->a_double);
          printf("the value of a non-initialized char is : %d\n\n", b->a_char);
      
          //test the pointers (in a global data structure)
          puts("tenth test : test the pointers (in a global data structure)");
          if(b->ptr_int == NULL) printf("a non-initialized int pointer is NULL\n");
          else printf("a non-initialized int pointer is not NULL\n");
          if(b->ptr_float == NULL) printf("a non-initialized float pointer is NULL\n");
          else printf("a non-initialized float pointer is not NULL\n");
          if(b->ptr_double == NULL) printf("a non-initialized double pointer is NULL\n");
          else printf("a non-initialized double pointer is not NULL\n");
          if(b->ptr_char == NULL) printf("a non-initialized char pointer is NULL\n\n");
          else printf("a non-initialized char pointer is not NULL\n\n");
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-16
        • 2017-11-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多