是否可以将C指针初始化为NULL?

时间:2017-04-11 06:15:27

标签: c pointers initialization

我一直在写像

这样的东西
char *x=NULL;

假设

 char *x=2;

将创建一个指向地址2的char指针。

但是,在The GNU C Programming Tutorial中,int *my_int_ptr = 2;表示2将整数值my_int_ptr存储到char *x=NULL中分配的随机地址。

这似乎意味着我自己的NULL正在将char强制转换为#include <stdlib.h> #include <stdio.h> int main() { char *x=NULL; if (x==NULL) printf("is NULL\n"); return EXIT_SUCCESS; } 的值分配给内存中的某个随机地址。

虽然

char *x;
x=NULL;
事实上,

确实打印

  

是NULL

当我编译并运行它时,我担心我依赖于未定义的行为,或者至少是指定不足的行为,我应该写

        // The admin requires some twig functions defined in the security
        // bundle, like is_granted. Register this bundle if it wasn't the case
        // already.
        new Symfony\Bundle\SecurityBundle\SecurityBundle(),

        // These are the other bundles the SonataAdminBundle relies on
        new Sonata\CoreBundle\SonataCoreBundle(),
        new Sonata\BlockBundle\SonataBlockBundle(),
        new Knp\Bundle\MenuBundle\KnpMenuBundle(),

        // And finally, the storage and SonataAdminBundle
        new Sonata\DoctrineORMAdminBundle\SonataDoctrineORMAdminBundle(),
        new Sonata\AdminBundle\SonataAdminBundle(),

代替。

9 个答案:

答案 0 :(得分:110)

  

是否可以将C指针初始化为NULL?

TL; DR 非常好。

The actual claim made on the guide reads like

  

另一方面,如果仅使用单个初始赋值int *my_int_ptr = 2;,程序将尝试填充my_int_ptr指向的内存位置的内容,值为2由于my_int_ptr充满了垃圾,它可以是任何地址。 [...]

嗯,他们 错了,你是对的。

对于语句,(忽略,现在指向整数转换的指针是一个实现定义的行为

int * my_int_ptr = 2;

my_int_ptr是一个变量(指向int的类型指针),它有一个自己的地址(类型:指向整数的指针的地址),你存储的值为{{1}进入那个地址。

现在,2,作为指针类型,我们可以说,指向 指向的内存位置的“type”值价值保持在my_int_ptr。因此,您实际上是指定 of 指针变量,而不是指针所指向的内存位置的值。

所以,结论

my_int_ptr

将指针变量 char *x=NULL; 初始化为x,而不是指针指向的内存地址的

相同
NULL

扩展:

现在,严格遵守,像

这样的陈述
 char *x;
 x = NULL;    

是非法的,因为它涉及约束违规。要清楚,

  • int * my_int_ptr = 2; 是指针变量,类型为my_int_ptr
  • 一个整数常量,int *根据定义具有类型2

并且它们不是“兼容”类型,因此这种初始化是无效的,因为它违反了Lundin's answer中描述的章节§6.5.16.1/ P1中提到的简单赋值规则。

如果有人对初始化与简单赋值约束的关联感兴趣,引用int,章节§6.7.9,P11

  

标量的初始值设定项应为单个表达式,可选择用大括号括起来。该   对象的初始值是表达式的初始值(转换后); 相同的类型   适用于简单赋值的约束和转换,采用标量的类型   成为其声明类型的非限定版本。

答案 1 :(得分:53)

教程错了。在ISO C中,int *my_int_ptr = 2;是一个错误。在GNU C中,它与int *my_int_ptr = (int *)2;相同。这会将整数2转换为内存地址,以编译器确定的某种方式。

它不会尝试在该地址所寻址的位置存储任何内容(如果有的话)。如果您继续撰写*my_int_ptr = 5;,那么它会尝试将号码5存储在该地址所针对的位置。

答案 2 :(得分:17)

为了澄清教程错误的原因,int *my_int_ptr = 2;是一个“约束违规”,它是不允许编译的代码,编译器必须在遇到它时给你一个诊断。

根据6.5.16.1简单分配:

  

约束

     

以下其中一项应成立:

     
      
  • 左操作数具有原子,限定或非限定算术类型,右边有算术类型;
  •   
  • 左操作数具有与右侧类型兼容的结构或联合类型的原子,限定或非限定版本;
  •   
  • 左操作数具有原子,限定或非限定指针类型,并且(考虑左值操作数在左值后的类型)   转换)两个操作数都是限定或不合格的指针   兼容类型的版本,以及左侧指向的类型   右边所指出的所有限定词;
  •   
  • 左操作数具有原子,限定或非限定指针类型,并且(考虑左值操作数在左值后的类型)   转换)一个操作数是指向对象类型的指针,另一个是   是一个指向有资格或不合格的void版本的指针   左边指向的类型具有指向的所有类型的限定符   在右边;
  •   
  • 左操作数是原子,限定或非限定指针,右边是空指针常量;或
  •   
  • 左操作数的类型为atomic,qualified或nonqualified _Bool,右边是指针。
  •   

在这种情况下,左操作数是一个非限定指针。它没有提到右操作数被允许为整数(算术类型)。所以代码违反了C标准。

除非您明确告诉GCC是标准C编译器,否则GCC会表现不佳。如果您将代码编译为-std=c11 -pedantic-errors,它将正确地提供必要的诊断。

答案 3 :(得分:15)

int *my_int_ptr = 2

  

将整数值2存储到my_int_ptr中的任何随机地址。

这是完全错误的。如果这是实际写的,那么请获得更好的书或教程。

int *my_int_ptr = 2定义一个指向地址2的整数指针。如果您尝试访问地址2,则很可能会崩溃。

*my_int_ptr = 2,即行中没有int,将值2存储到指向的任意随机地址my_int_ptr。说完这个之后,您可以在定义时将NULL指定给指针。 char *x=NULL;完全有效C.

编辑:在写这篇文章时我不知道指针转换的整数是实现定义的行为。请查看@ M.M和@SouravGhosh的详细答案。

答案 4 :(得分:14)

关于C指针的许多混淆来自于最初针对编码风格做出的非常糟糕的选择,并且通过语言语法中的一个非常糟糕的小选择得到了证实。

int *x = NULL;是正确的C,但这是非常误导,我甚至会说荒谬,并且它阻碍了许多新手对语言的理解。这让人觉得以后我们可以做*x = NULL;,这当然是不可能的。您可以看到,变量的类型不是int,变量的名称不是*x,声明中的*也不会与{合作}发挥任何功能作用{1}}。这纯粹是陈述性的。因此,更有意义的是:

=这也是正确的C,尽管它不符合原始的K&amp; R编码风格。它非常清楚地表明类型是int* x = NULL;,并且指针变量是int*,所以即使对于没有经验的人来说,值x被存储到{{1}中也很明显。 },这是指向NULL的指针。

此外,它更容易派生规则:当星星远离变量名称时,它就是一个声明,而附加到名称的星号是指针解除引用。

所以,现在变得更容易理解的是,我们可以进一步向xint进行操作,换句话说,它让新手更容易看到x = NULL;如何导致*x = 2;variable = expression。 (对于发起的,表达方式&#39;我的意思是&#39; rvalue&#39;。)

语言语法中的不幸选择是,在声明局部变量时,您可以说pointer-type variable = pointer-expression声明一个整数和指向整数的指针,因此它会让人相信dereferenced-pointer-variable = expression是名称的有用部分。但事实并非如此,这种语法只是一个古怪的特殊情况,为方便起见而添加,在我看来它应该从未存在过,因为它使我上面提出的规则无效。据我所知,语言中没有其他地方是这种语法有意义,但即使它是,它指的是指针类型在C中定义的方式的差异。在其他地方,在单变量声明中,在参数列表中,在struct members等中,您可以将指针声明为int i, *p;而不是*;它是完全合法的,更有意义。

答案 5 :(得分:6)

我想补充一些与许多优秀答案正交的东西。实际上,初始化为NULL远非不好的做法,如果该指针可能会或可能不会用于存储动态分配的内存块,则可能很方便。

int * p = NULL;
...
if (...) {
    p = (int*) malloc(...);
    ...
}
...
free(p);

由于根据ISO-IEC 9899 standard free在参数为NULL时是一个nop,上面的代码(或者在同一行中更有意义的东西)是合法的。

答案 6 :(得分:1)

这是一个空指针

int * nullPtr = (void*) 0;

答案 7 :(得分:1)

这是正确的。

int main()
{
    char * x = NULL;

    if (x==NULL)
        printf("is NULL\n");

    return EXIT_SUCCESS;
}

此功能对于它的功能是正确的。它将地址0指定给char指针x。也就是说,它将指针x指向存储器地址0。

替代:

int main()
{
    char* x = 0;

    if ( !x )
        printf(" x points to NULL\n");

    return EXIT_SUCCESS;
}

我猜你想要的是:

int main()
{
    char* x = NULL;
    x = alloc( sizeof( char ));
    *x = '2';

    if ( *x == '2' )
        printf(" x points to an address/location that contains a '2' \n");

    return EXIT_SUCCESS;
}

x is the street address of a house. *x examines the contents of that house.

答案 8 :(得分:-2)

请记住:

在C中,左侧值始终计算到内存位置,而右侧始终计算为值(无论是int还是地址或类Foo)。