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

我一直在写东西

char *x=NULL; 

假设

  char *x=2; 

会创build一个char指针到地址2。

但是,在GNU C编程教程中,它说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; } 

事实上,打印

一片空白

当我编译和运行它时,我担心的是我依赖于未定义的行为,或者至less是不明确的行为,而且我应该写

 char *x; x=NULL; 

代替。

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

TL; DR是的,非常。


在指南上提出实际要求是这样的

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

那么他们错了,你是对的。

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

 int * my_int_ptr = 2; 

my_int_ptr是一个variables(指向inttypes的指针),它有一个自己的地址(types:指向整数的指针的地址),你将值2存储到地址。

现在, my_int_ptr是一个指针types,我们可以说,它指向 my_int_ptr保存的值指向的内存位置的“type”值。 所以,你基本上是分配指针variables的值,而不是指针指向的内存位置的值。

所以,结论

  char *x=NULL; 

将指针variablesx初始化为NULL ,而不是指针指向的内存地址

这是一样

  char *x; x = NULL; 

扩张:

现在,严格遵守,像一个声明

  int * my_int_ptr = 2; 

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

  • my_int_ptr是一个指针variables,types为int *
  • 一个整数常量, 2的定义是inttypes。

而且它们不是“兼容的”types,所以这个初始化是无效的,因为它违反了简单赋值的规则,这在Lundin的答案中描述的§6.5.16.1/ P1中提到。

如果有人对初始化如何链接到简单的赋值约束感兴趣,引用C11第6.7.9节,P11

标量的初始值应该是一个单独的expression式,可以用大括号括起来。 对象的初始值是expression式(转换后)的初始值; 与简单赋值相同的types约束和转换适用,将标量types作为其声明types的非限定版本。

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

它不会尝试在该地址所在的位置存储任何内容(如果有的话)。 如果你继续写*my_int_ptr = 5; ,那么它会尝试将数字5存储在该地址所指向的位置。

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

按照6.5.16.1简单赋值:

约束

下列其中一项应为:

  • 左边的操作数具有primefaces性,合格性或不合格的算术types,右边有算术types;
  • 左操作数具有与右侧types兼容的结构或联合types的primefaces,限定或不合格版本;
  • 左操作数具有primefaces,限定或非限定指针types,并且(考虑左值在左值转换后将具有的types),两个操作数都是指向兼容types的限定版本或非限定版本的指针,而左边指向的types具有全部右边指出的types限定符;
  • 左操作数具有primefaces性,限定性或非限定性指针types,并且(考虑左值在左值转换后将具有的types),一个操作数是指向对象types的指针,另一个是指向合格或不合格版本的指针void,左边指向的types具有右侧指向的所有types的限定符;
  • 左边的操作数是一个primefaces,限定或不合格的指针,右边是一个空指针常量; 要么
  • 左操作数具有typesprimefaces,限定或不合格的_Bool,右边是一个指针。

在这种情况下,左操作数是一个不合格的指针。 它没有提到允许右操作数是一个整数(算术types)。 所以代码违反了C标准。

GCC被称为行为不佳,除非你明确地告诉它是一个标准的C编译器。 如果将代码编译为-std=c11 -pedantic-errors ,它将正确地给出诊断,因为它必须执行。

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指向。 说了这个之后,你可以在定义的时候给指针赋NULLchar *x=NULL; 是完全有效的C.

编辑:在写这个时,我不知道整型指针转换是实现定义的行为。 有关详细信息,请参阅@MM和@SouravGhosh的良好答案。

关于C语言指针的许多困惑都来自于最初编码风格的一个非常糟糕的select,这在语言的语法中是非常糟糕的select。

int *x = NULL; 是正确的C,但这是非常误导的,我甚至会说无意义的,它已经阻碍了许多新手对语言的理解。 这让人想到以后我们可以做*x = NULL; 这当然是不可能的。 你看,variables的types不是int ,variables的名称不是*x ,声明中的*也不能和=协同起作用。 这是纯粹的声明。 所以,更重要的是这个:

int* x = NULL; 这也是正确的C,虽然它不符合原来的K&R编码风格。 它清楚地表明types是int* ,指针variables是x ,所以即使对于不熟悉的事实,值NULL也被存储到x ,这是一个指向int的指针。

此外,它更容易推导出一条规则:当星星离开variables名称时,它是一个声明,而附加到名称的星号是指针解除引用。

所以,现在变得更容易理解,进一步下来,我们可以做x = NULL;*x = 2; 换句话说,它使新手更容易看到variable = expression如何导致pointer-type variable = pointer-expressiondereferenced-pointer-variable = expression 。 (对于发起者来说,“expression”我的意思是“右值”)。

语言语法中不幸的select是当声明局部variables时,你可以说int i, *p; 它声明了一个整数和一个指向整数的指针,所以它使人相信*是名字的一个有用部分。 但事实并非如此,这句话只是一个古怪的特例,为方便起见,我认为它应该从来没有存在,因为它使我上面提出的规则无效。 据我所知,语言中没有其他地方的语法是有意义的,但即使是这样,它也指向了在C中定义指针types的方式上的差异。在其他地方,在单variables声明中,在参数列表中,在结构成员等,你可以声明你的指针type* pointer-variable而不是type *pointer-variable ; 这是完全合法的,更有意义。

我想添加一些与许多优秀答案正交的东西。 实际上,初始化为NULL远不是坏习惯,如果该指针可能或不可用于存储dynamic分配的内存块,则可能会很方便。

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

由于根据ISO-IEC 9899标准,当参数为NULLfree是一个nop,所以上面的代码(或者在同一行上更有意义)是合法的。

这是一个空指针

 int * nullPtr = (void*) 0; 

这是对的。

 int main() { char * x = NULL; if (x==NULL) printf("is NULL\n"); return EXIT_SUCCESS; } 

这个function是正确的。 它将0的地址赋给字符指针x。 也就是说,它将指针x指向内存地址0。

替代scheme:

 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. 

只要记住:

在C中, 左侧值总是评估一个内存位置 ,而右侧总是评估一个值(无论是int或地址或类Foo)。