C语言 是否可以将 C 指针初始化为 NULL?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43338084/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible to initialize a C pointer to NULL?
提问by fagricipni
I had been writing things like
我一直在写这样的东西
char *x=NULL;
on the assumption that
假设
char *x=2;
would create a charpointer to address 2.
将创建一个char指向地址 2的指针。
But, in The GNU C Programming Tutorialit says that int *my_int_ptr = 2;stores the integer value 2to whatever random address is in my_int_ptrwhen it is allocated.
但是,在GNU C 编程教程中,它说int *my_int_ptr = 2;将整数值存储2到my_int_ptr分配时所在的任何随机地址。
This would seem to imply that my own char *x=NULLis assigning whatever the value of NULLcast to a charis to some random address in memory.
这似乎暗示我自己char *x=NULL正在将NULLcast 的任何值分配给char内存中的某个随机地址。
While
尽管
#include <stdlib.h>
#include <stdio.h>
int main()
{
char *x=NULL;
if (x==NULL)
printf("is NULL\n");
return EXIT_SUCCESS;
}
does, in fact, print
事实上,打印
is NULL
一片空白
when I compile and run it, I am concerned that I am relying on undefined behavior, or at least under-specified behavior, and that I should write
当我编译和运行它时,我担心我依赖于未定义的行为,或者至少是未指定的行为,我应该写
char *x;
x=NULL;
instead.
反而。
回答by Sourav Ghosh
Is it possible to initialize a C pointer to NULL?
是否可以将 C 指针初始化为 NULL?
TL;DRYes, very much.
TL;DR是的,非常。
The actual claim made on the guidereads like
On the other hand, if you use just the single initial assignment,
int *my_int_ptr = 2;, the program will try to fill the contents of the memory location pointed to bymy_int_ptrwith the value 2. Sincemy_int_ptris filled with garbage, it can be any address. [...]
另一方面,如果您只使用单个初始赋值,
int *my_int_ptr = 2;,程序将尝试my_int_ptr用值 2my_int_ptr填充指向的内存位置的内容。由于填充了垃圾,它可以是任何地址。[...]
Well, they arewrong, you are right.
那么,他们是错的,你是对的。
For the statement, (ignoring, for now, the fact that pointer to integer conversion is an implementation-defined behaviour)
对于语句,(暂时忽略指向整数转换的指针是实现定义的行为这一事实)
int * my_int_ptr = 2;
my_int_ptris a variable (of type pointer to int), it has an address of its own (type: address of pointer to integer), you are storing a value of 2into thataddress.
my_int_ptr是一个变量(指向 的类型int),它有自己的地址(类型:指向整数的指针的地址),您将 的值存储2到该地址中。
Now, my_int_ptr, being a pointer type, we can say, it points tothe value of "type" at the memory location pointed bythe value held in my_int_ptr. So, you are essentially assigning the value ofthe pointer variable, not the value of the memory location pointed to by the pointer.
现在my_int_ptr,作为一个指针类型,我们可以说,它指向的内存位置的“类型”的值,通过指出在保存的值my_int_ptr。所以,你基本上是将值的指针变量,存储位置不是值由指针指向。
So, for conclusion
所以,结论
char *x=NULL;
initializes the pointer variable xto NULL, not the value at the memory address pointed to by the pointer.
将指针变量初始化x为NULL,而不是指针指向的内存地址处的值。
This is the sameas
这是相同的
char *x;
x = NULL;
Expansion:
扩张:
Now, being strictly conforming, a statement like
现在,严格遵守,像这样的声明
int * my_int_ptr = 2;
is illegal, as it involves constraint violation. To be clear,
是非法的,因为它涉及违反约束。要清楚,
my_int_ptris a pointer variable, typeint *- an integer constant,
2has typeint, by definition.
my_int_ptr是一个指针变量,类型int *- 一个整数常量,根据定义
2具有 typeint。
and they are not "compatible" types, so this initialization is invalid because it's violating the rules of simple assignment, mentioned in chapter §6.5.16.1/P1, described in Lundin's answer.
并且它们不是“兼容”类型,因此此初始化无效,因为它违反了在Lundin 的回答中描述的第 §6.5.16.1/P1 章中提到的简单赋值规则。
In case anyone's interested how initialization is linked to simple assignment constraints, quoting C11, chapter §6.7.9, P11
如果有人对初始化如何链接到简单的赋值约束感兴趣,请引用C11第 6.7.9 章,P11
The initializer for a scalar shall be a single expression, optionally enclosed in braces. The initial value of the object is that of the expression (after conversion); the same type constraints and conversions as for simple assignment apply, taking the type of the scalar to be the unqualified version of its declared type.
标量的初始值设定项应为单个表达式,可选地括在大括号中。对象的初始值是表达式的初始值(转换后);与简单赋值相同的类型约束和转换适用,将标量的类型作为其声明类型的非限定版本。
回答by M.M
The tutorial is wrong. In ISO C, int *my_int_ptr = 2;is an error. In GNU C, it means the same as int *my_int_ptr = (int *)2;. This converts the integer 2to a memory address, in some fashion as determined by the compiler.
教程错了。在 ISO C 中,int *my_int_ptr = 2;是一个错误。在 GNU C 中,它与int *my_int_ptr = (int *)2;. 这2以编译器确定的某种方式将整数转换为内存地址。
It does not attempt to store anything in the location addressed by that address (if any). If you went on to write *my_int_ptr = 5;, then it would try to store the number 5in the location addressed by that address.
它不会尝试在该地址(如果有)寻址的位置中存储任何内容。如果你继续写*my_int_ptr = 5;,那么它会尝试将数字存储5在该地址寻址的位置。
回答by Lundin
To clarify why the tutorial is wrong, int *my_int_ptr = 2;is a "constraint violation", it is code which is not allowed to compile and the compiler must give you a diagnostic upon encountering it.
澄清为什么教程是错误的,int *my_int_ptr = 2;是“违反约束”,它是不允许编译的代码,编译器必须在遇到它时给你一个诊断。
As per 6.5.16.1 Simple assignment:
根据 6.5.16.1 简单赋值:
Constraints
One of the following shall hold:
- the left operand has atomic, qualified, or unqualified arithmetic type, and the right has arithmetic type;
- the left operand has an atomic, qualified, or unqualified version of a structure or union type compatible with the type of the right;
- the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;
- the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) one operand is a pointer to an object type, and the other is a pointer to a qualified or unqualified version of void, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;
- the left operand is an atomic, qualified, or unqualified pointer, and the right is a null pointer constant; or
- the left operand has type atomic, qualified, or unqualified _Bool, and the right is a pointer.
约束
符合下列条件之一:
- 左操作数具有原子、限定或非限定算术类型,右侧具有算术类型;
- 左操作数具有与右操作数兼容的结构或联合类型的原子、限定或非限定版本;
- 左操作数具有原子的、限定的或非限定的指针类型,并且(考虑左操作数在左值转换后的类型)两个操作数都是指向兼容类型的限定或非限定版本的指针,并且左侧指向的类型具有所有右边所指类型的限定符;
- 左操作数具有原子的、限定的或非限定的指针类型,并且(考虑左操作数在左值转换后将具有的类型)一个操作数是指向对象类型的指针,另一个是指向限定或未限定版本的指针void,左边指向的类型具有右边指向的类型的所有限定符;
- 左操作数是原子的、限定的或非限定的指针,右操作数是空指针常量;或者
- 左操作数的类型是原子的、限定的或非限定的 _Bool,右操作数是一个指针。
In this case the left operand is an unqualified pointer. Nowhere does it mention that the right operand is allowed to be an integer (arithmetic type). So the code violates the C standard.
在这种情况下,左操作数是一个非限定指针。它没有提到允许正确的操作数是整数(算术类型)。所以代码违反了C标准。
GCC is known to behave poorly unless you explicitly tell it to be a standard C compiler. If you compile the code as -std=c11 -pedantic-errors, it will correctly give a diagnostic as it must do.
众所周知,除非您明确告诉 GCC 是标准的 C 编译器,否则 GCC 的行为很差。如果您将代码编译为-std=c11 -pedantic-errors,它将正确地给出必须做的诊断。
回答by taskinoor
int *my_int_ptr = 2
int *my_int_ptr = 2
stores the integer value 2 to whatever random address is in my_int_ptr when it is allocated.
分配时将整数值 2 存储到 my_int_ptr 中的任何随机地址。
This is completely wrong. If this is actually written then please get a better book or tutorial.
这是完全错误的。如果这是真的,那么请找一本更好的书或教程。
int *my_int_ptr = 2defines an integer pointer which points to address 2. You will most likely get a crash if you try to access address 2.
int *my_int_ptr = 2定义了一个指向地址 2 的整数指针。如果您尝试访问 address ,您很可能会崩溃2。
*my_int_ptr = 2, i.e. without the intin the line, stores the value two to whatever random address my_int_ptris pointing to. Having saying this, you can assign NULLto a pointer when it is defined. char *x=NULL;is perfectly valid C.
*my_int_ptr = 2,即没有intin 行,将值 2 存储到my_int_ptr指向的任何随机地址。话虽如此,您可以NULL在定义指针时为其赋值。char *x=NULL;完全有效 C.
Edit: While writing this I didn't know that integer to pointer conversion is implementation defined behavior. Please see the good answers by @M.M and @SouravGhosh for details.
编辑:在写这篇文章时,我不知道整数到指针的转换是实现定义的行为。有关详细信息,请参阅 @MM 和 @SouravGhosh 的好答案。
回答by Mike Nakis
A lot of confusion about C pointers comes from a very bad choice that was originally made regarding coding style, corroborated by a very bad little choice in the syntax of the language.
很多关于 C 指针的混淆来自于最初在编码风格方面做出的一个非常糟糕的选择,而语言语法中一个非常糟糕的小选择也证实了这一点。
int *x = NULL;is correct C, but it is very misleading, I would even say nonsensical, and it has hindered the understanding of the language for many a novice. It makes one think that later on we could do *x = NULL;which is of course impossible. You see, the type of the variable is not int, and the name of the variable is not *x, nor does the *in the declaration play any functional role in collaboration with the =. It is purely declarative. So, what makes a lot more sense is this:
int *x = NULL;是正确的C,但它非常具有误导性,我什至会说是无稽之谈,它阻碍了许多新手对语言的理解。这让人认为以后我们可以做到*x = NULL;这当然是不可能的。你看,变量的类型不是int,变量的名字不是*x,*声明中的也没有与 配合起任何功能作用=。它纯粹是声明性的。所以,更有意义的是:
int* x = NULL;which is also correct C, albeit it does not adhere to the original K&R coding style. It makes it perfectly clear that the type is int*, and the pointer variable is x, so it becomes plainly evident even to the uninitiated that the value NULLis being stored into x, which is a pointer to int.
int* x = NULL;这也是正确的 C,尽管它不遵循原始的 K&R 编码风格。它清楚地表明类型是int*,而指针变量是x,因此即使对于未初始化的人来说,值NULL被存储到 中也很明显x,这是一个指向 的指针int。
Furthermore, it makes it easier to derive a rule: when the star is away from the variable name then it is a declaration, while the star being attached to the name is pointer dereferencing.
此外,它更容易推导出一条规则:当星号远离变量名称时,它是一个声明,而附加到名称上的星号是指针解引用。
So, now it becomes a lot more understandable that further down we can either do x = NULL;or *x = 2;in other words it makes it easier for a novice to see how variable = expressionleads to pointer-type variable = pointer-expressionand dereferenced-pointer-variable = expression. (For the initiated, by 'expression' I mean 'rvalue'.)
所以,现在更容易理解的是,我们可以做进一步的工作,x = NULL;或者*x = 2;换句话说,它使新手更容易看到如何variable = expression导致pointer-type variable = pointer-expression和dereferenced-pointer-variable = expression。(对于初始,“表达式”我的意思是“右值”。)
The unfortunate choice in the syntax of the language is that when declaring local variables you can say int i, *p;which declares an integer and a pointer to an integer, so it leads one to believe that the *is a useful part of the name. But it is not, and this syntax is just a quirky special case, added for convenience, and in my opinion it should have never existed, because it invalidates the rule that I proposed above. As far as I know, nowhere else in the language is this syntax meaningful, but even if it is, it points to a discrepancy in the way pointer types are defined in C. Everywhere else, in single-variable declarations, in parameter lists, in struct members, etc. you can declare your pointers as type* pointer-variableinstead of type *pointer-variable; it is perfectly legal and makes more sense.
该语言语法中的一个不幸选择是,在声明局部变量时,您可以说int i, *p;which 声明了一个整数和一个指向整数的指针,因此它使人们相信 the*是名称的有用部分。但事实并非如此,这种语法只是一个古怪的特例,为了方便而添加,在我看来它本不应该存在,因为它使我上面提出的规则无效。据我所知,这种语法在语言中的其他任何地方都没有意义,但即使是这样,它也表明在 C 中定义指针类型的方式存在差异。在其他任何地方,在单变量声明中,在参数列表中,在结构成员等中,您可以将指针声明为,type* pointer-variable而不是type *pointer-variable; 这是完全合法的,更有意义。
回答by Luca Citi
I would like to add something orthogonal to the many excellent answers. Actually, initializing to NULLis far from bad practice and may be handy if that pointer may or may not be used to store a dynamically allocated block of memory.
我想添加一些与许多优秀答案正交的东西。实际上,初始化NULL为远非坏习惯,如果该指针可能用于或可能不用于存储动态分配的内存块,则可能很方便。
int * p = NULL;
...
if (...) {
p = (int*) malloc(...);
...
}
...
free(p);
Since according to the ISO-IEC 9899 standardfreeis a nop when the argument is NULL, the code above (or something more meaningful along the same lines) is legit.
由于根据ISO-IEC 9899 标准,free当参数为 时是 nop NULL,因此上面的代码(或类似的更有意义的代码)是合法的。
回答by Ahmed Nabil El-Gawahergy
this is a null pointer
这是一个空指针
int * nullPtr = (void*) 0;
回答by Vanderdecken
This is correct.
这是对的。
int main()
{
char * x = NULL;
if (x==NULL)
printf("is NULL\n");
return EXIT_SUCCESS;
}
This function is correct for what it does. It assigns the address of 0 to the char pointer x. That is, it points the pointer x to the memory address 0.
这个函数的作用是正确的。它将地址 0 分配给 char 指针 x。也就是说,它将指针 x 指向内存地址 0。
Alternative:
选择:
int main()
{
char* x = 0;
if ( !x )
printf(" x points to NULL\n");
return EXIT_SUCCESS;
}
My guess as to what you wanted is:
我对你想要的东西的猜测是:
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.

