fag*_*pni 88 c pointers initialization
我一直在写类似的东西
char *x=NULL;
Run Code Online (Sandbox Code Playgroud)
假设是
char *x=2;
Run Code Online (Sandbox Code Playgroud)
会创建一个char
指向地址2 的指针.
但是,在GNU C编程教程中,它表示int *my_int_ptr = 2;
将整数值存储2
到my_int_ptr
分配时的任何随机地址.
这似乎意味着我自己char *x=NULL
正在将NULL
一个cast 的值分配给char
内存中的某个随机地址.
而
#include <stdlib.h>
#include <stdio.h>
int main()
{
char *x=NULL;
if (x==NULL)
printf("is NULL\n");
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
事实上,印刷品
一片空白
当我编译并运行它时,我担心我依赖于未定义的行为,或者至少是指定不足的行为,我应该写
char *x;
x=NULL;
Run Code Online (Sandbox Code Playgroud)
代替.
Sou*_*osh 111
是否可以将C指针初始化为NULL?
TL; DR是的,非常.
另一方面,如果你只使用单个初始赋值,
int *my_int_ptr = 2;
程序将尝试my_int_ptr
用值2my_int_ptr
填充指向的内存位置的内容.由于填充了垃圾,它可以是任何地址.[...]
那么,他们是错的,你是对的.
对于语句,(暂时忽略指向整数转换的指针是一个实现定义的行为)
int * my_int_ptr = 2;
Run Code Online (Sandbox Code Playgroud)
my_int_ptr
是一个变量(类型指针int
),它有一个自己的地址(类型:指向整数的指针的地址),你将一个值存储2
到该地址.
现在,my_int_ptr
作为指针类型,我们可以说,它指向保存在的值指向的内存位置的"类型" 的值my_int_ptr
.所以,你基本上是将值的指针变量,存储位置不是值由指针指向.
所以,结论
char *x=NULL;
Run Code Online (Sandbox Code Playgroud)
将指针变量初始化x
为NULL
,而不是指针指向的内存地址的值.
这是一样的
char *x;
x = NULL;
Run Code Online (Sandbox Code Playgroud)
现在,严格遵守,声明如
int * my_int_ptr = 2;
Run Code Online (Sandbox Code Playgroud)
是非法的,因为它涉及约束违规.要清楚,
my_int_ptr
是一个指针变量,类型 int *
2
具有类型int
.并且它们不是"兼容"类型,因此这种初始化是无效的,因为它违反了简单赋值的规则,在Lundin的答案中描述的章节§6.5.16.1/ P1中提到.
如果有人对初始化如何与简单赋值约束,引用C11
,章节§6.7.9,P11 相关联感兴趣
标量的初始值设定项应为单个表达式,可选择用大括号括起来.对象的初始值是表达式的初始值(转换后); 与简单赋值相同的类型约束和转换适用,将标量的类型作为其声明类型的非限定版本.
M.M*_*M.M 53
该教程是错误的.在ISO C中,int *my_int_ptr = 2;
是一个错误.在GNU C中,它的含义相同int *my_int_ptr = (int *)2;
.这会2
以编译器确定的某种方式将整数转换为内存地址.
它不会尝试在该地址所寻址的位置存储任何内容(如果有的话).如果你继续写*my_int_ptr = 5;
,那么它会尝试将该号码存储5
在该地址所寻址的位置.
Lun*_*din 17
为了澄清教程错误的原因,int *my_int_ptr = 2;
是"约束违规",它是不允许编译的代码,编译器必须在遇到它时给你一个诊断.
根据6.5.16.1简单分配:
约束
以下其中一项应持有:
- 左操作数具有原子,限定或非限定算术类型,右边有算术类型;
- 左操作数具有与右侧类型兼容的结构或联合类型的原子,限定或非限定版本;
- 左操作数具有原子,限定或非限定指针类型,并且(考虑左值操作数在左值转换后将具有的类型)两个操作数都是指向兼容类型的限定或非限定版本的指针,左侧指向的类型具有全部右边指出的那种限定词;
- 左操作数具有原子,限定或非限定指针类型,并且(考虑左值操作数在左值转换后将具有的类型)一个操作数是指向对象类型的指针,另一个是指向合格或非限定版本的指针void,左边指向的类型具有右边指向的所有类型的限定符;
- 左操作数是一个原子,限定或非限定指针,右边是一个空指针常量; 要么
- 左操作数的类型为atomic,qualified或nonqualified _Bool,右边是指针.
在这种情况下,左操作数是一个不合格的指针.它没有提到右操作数被允许为整数(算术类型).所以代码违反了C标准.
众所周知,GCC表现不佳,除非您明确告诉它是标准的C编译器.如果您将代码编译为-std=c11 -pedantic-errors
,它将正确地提供必要的诊断.
tas*_*oor 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.
编辑:写这篇文章时我不知道指针转换的整数是实现定义的行为.有关详细信息,请参阅@MM和@SouravGhosh的好答案.
Mik*_*kis 14
关于C指针的许多混淆来自于最初针对编码风格做出的非常糟糕的选择,这是由语言语法中的一个非常糟糕的小选择所证实的.
int *x = NULL;
是正确的C,但它是非常误导,我甚至会说荒谬,并且它阻碍了许多新手对语言的理解.它让人觉得以后我们可以做到*x = NULL;
这当然是不可能的.你看,变量的类型不是int
,变量的名称不是*x
,*
声明中的声明也没有起到任何作用=
.这纯粹是陈述性的.那么,更有意义的是:
int* x = NULL;
这也是正确的C,虽然它不符合原始的K&R编码风格.它非常清楚地表明类型是int*
,并且指针变量是x
,所以即使对于未经证实的值NULL
存储到的值,它也变得明显x
,这是指向它的指针int
.
此外,它更容易派生规则:当星号远离变量名称时,它是一个声明,而附加到名称的星号是指针解除引用.
所以,现在变得更容易理解,我们可以做到更进一步,x = NULL;
或者*x = 2;
换句话说,它让新手更容易看到如何variable = expression
导致pointer-type variable = pointer-expression
和dereferenced-pointer-variable = expression
.(对于发起的,'表达'我的意思是'rvalue'.)
语言语法中的不幸选择是,在声明局部变量时,您可以说int i, *p;
哪个声明了一个整数和一个指向整数的指针,因此它使人们相信它*
是名称的一个有用部分.但事实并非如此,这种语法只是一个古怪的特殊情况,为方便起见而添加,在我看来它应该从未存在过,因为它使我上面提出的规则无效.据我所知,语言中没有其他地方是这种语法有意义,但即使它是,它指的是指针类型在C中定义的方式的差异.在其他地方,在单变量声明中,在参数列表中,在struct members等中你可以声明你的指针type* pointer-variable
而不是type *pointer-variable
; 它是完全合法的,更有意义.
我想补充一些与许多优秀答案正交的东西.实际上,NULL
如果指针可能会或可能不会用于存储动态分配的内存块,则初始化为非常糟糕的做法并且可能很方便.
int * p = NULL;
...
if (...) {
p = (int*) malloc(...);
...
}
...
free(p);
Run Code Online (Sandbox Code Playgroud)
因为根据ISO-IEC 9899标准, free
当论证是一个nop时NULL
,上面的代码(或者沿着相同的行更有意义的东西)是合法的.