直接声明并赋值给C指针

时间:2015-09-27 00:45:14

标签: c pointers

我已阅读

Directly assigning values to C Pointers

但是,我试图了解这种不同的情况......

int *ptr = 10000;
printf("value: %d\n", ptr);
printf("value: %d\n", *ptr);

我在第二个printf上遇到了分段错误。

现在,我认为10000是一个内存位置,因为指针指向内存中的地址。我也知道10000可以在内存中的任何地方(可能已被其他一些进程占用)

因此,我在想第一个印刷品只是说“好吧,只要给我一个地址的值作为一个整数值”,所以,好吧,我得到了10000。

然后我说“好吧,现在尊重它”,但我没有把任何东西放进去(或者它是未初始化的)所以我遇到了分段错误。

也许我的逻辑已经完全脱离了轨道而且这一点。

已更新::::

感谢所有快速回复..所以这是我的理解。

首先,     int * ptr = 10000; 是UB,因为我无法指定一个常量值的指针。

其次,以下也是UB,因为我使用%d而不是使用%p。     printf(“value:%d \ n”,ptr)

第三,我已经给出了一个地址(虽然它是UB),但是我还没有初始化为某个值,所以下面的语句得到了seg错误。     print(“value:%d \ n”,* ptr)

我的理解现在正确吗?

感谢。

3 个答案:

答案 0 :(得分:2)

int *ptr = 10000;

这不仅仅是未定义的行为。这是约束违规

表达式10000的类型为intptr的类型为int*。没有从intint*的隐式转换(除了空指针常量的特殊情况,此处不适用)。

任何符合C的编译器,在处理此声明时,必须发出诊断消息。允许该消息成为非致命警告,但一旦发出该消息,该程序的行为就不确定。

编译器可能会将其视为致命错误,并拒绝编译您的程序。 (在我看来,编译器应该这样做。)

如果你真的想指定ptr指向地址10000,你可以写一下:

int *ptr = (int*)10000;

intint*没有隐式转换,但您可以使用强制转换运算符进行显式转换。

如果您碰巧知道10000是您的代码将运行的机器的有效地址,那么这是一件有用的事情。但是一般来说,将整数转换为指针"的结果是实现定义的,可能没有正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示" (N1570第6.3.2.3节)。如果10000不是有效地址(并且很可能不是),那么即使您尝试访问指针的值,您的程序仍会有未定义的行为,但特别是如果您尝试取消引用它。

这也假设将整数值10000转换为指针类型是有意义的。通常这种转换会复制数值的位,但C标准并没有这样说。它可能会对数字进行一些奇怪的实现定义转换以生成地址。

地址(指针值)不是数字

printf("value: %d\n", ptr);

这肯定有未定义的行为。 %d格式需要int个参数。在许多系统上,intint*的大小相同。如果整数和指针不以相同的方式作为函数参数传递,那么最终可能会打印指针值的高位一半,甚至是一些完整的垃圾。要打印指针,请使用%p并将指针转换为void*

printf("value: %p\n", (void)ptr);

最后:

printf("value: %d\n", *ptr);

格式字符串是正确的,但仅评估*ptr具有未定义的行为(除非(int*)10000恰好是有效地址)。

请注意"未定义的行为"并不意味着你的程序会崩溃。这意味着标准说 nothing 关于运行它时会发生什么。 (崩溃可能是最佳可能的结果;它显然存在一个错误。)

答案 1 :(得分:1)

不,定义int *ptr = 10000没有给出未定义的行为。

它将文字值10000转换为指针,并使用该值初始化ptr

但是,在你的例子中

int *ptr = 10000;
printf("value: %d\n", ptr);
printf("value: %d\n", *ptr);

两个printf()语句都给出了未定义的行为。

第一个给出了未定义的行为,因为%d格式告诉printf()相应的参数是int类型,ptr不是。在实践中(对于大多数编译器/库),它通常会愉快地打印值10000,但这是偶然的。基本上(并且有点过于简单),为此发生,往返转换(例如,将10000int转换为指针,然后将该指针值转换为int )需要给出相同的价值。虽然在某些实现中确实发生了这种往返,但仍然无法保证,所以尽管涉及未定义的行为,但第一个printf()可能表现得很好。

未定义行为的部分问题是,一个可能的结果是代码表现得像程序员所期望的那样。这并没有定义行为。它只是意味着一组特定的情况(编译器,操作系统,硬件等的行为)恰好合谋给出对程序员来说似乎合理的行为。

第二个printf()语句提供了未定义的行为,因为它取消引用ptr。该标准没有给出期望具有值10000的指针特别对应于任何东西的基础。它可能是RAM中的一个位置。它可能是视频内存中的一个位置。它可能是一个与计算机上存在的内存中任何位置不对应的值。它可能是您的操作系统认为您的进程不允许访问的逻辑或物理内存位置(这实际上是导致多个操作系统下的访问冲突的原因,然后该操作系统向运行程序的进程发送信号,指示它终止)。

许多C编译器(如果配置得当)将对ptr的初始化发出警告 - 因为这样的初始化对编译器来说更容易检测,并且通常表示后续代码中存在问题。

答案 2 :(得分:0)

这可能会导致未定义的行为,因为从10000转换的指针可能无效。

您的操作系统可能不允许您的程序访问地址10000,因此会引发分段错误。

int *x = some numerical value (i.e. 10, whatever)

可能适用于微型计算机或低级计算机(例如:创建操作系统)。