1

这是程序:

#include <stdio.h>

main() {
  int * i;
  int * j;
  printf("%d\n", i);
  printf("%d\n", j);
}

我编译并运行它,输出是:

888086464
0

但是,如果我注释掉第二个 printf

#include <stdio.h>

main() {
  int * i;
  int * j;
  printf("%d\n", i);
  //printf("%d\n", j);
}

输出beomes:

0

我想知道为什么第二个 printf 会更改指针 i。
而且,C 是如何初始化指针的?据我所知,如果指针未初始化,它的值 Null 将等于 0,对吗?为什么在第一个输出中, i 被初始化?

编辑:根据你们的建议,我做了一些改变:

#include <stdio.h>

main() {
  int * i;
  int * j;
  printf("%p\n", i);
  printf("%p\n", j);
}

这使

0x7fff67a361b0
(nil)

但是当我注释掉第二个 printf

#include <stdio.h>

main() {
  int * i;
  int * j;
  printf("%p\n", i);
  //printf("%p\n", j);
}

输出为零。我很好奇为什么在有两个 printf 的第一个版本中,只有 j 是 nil 而 i 不是。

4

8 回答 8

4

您没有初始化任何一个指针。您正在查看的是未定义的行为。您看到的值只是堆栈中的垃圾值,每次运行时都可能更改。

于 2013-03-12T16:22:46.523 回答
3

如果您没有初始化指针,它可以有任何值。

必须初始化它们。否则你会得到一个undefined behavior.

指针打印的正确方法是:

printf("%p", pointer);
于 2013-03-12T16:22:19.130 回答
2

您可以通过查看为两个版本生成的机器代码来回答您的问题(对于 gcc,这应该是 -S 选项)。

怀疑在第二个版本中,j根本没有创建(因为它没有在任何地方使用),所以i在本来用于j. 无论出于何种原因,您的堆栈设置为使前 64 位0x0000000000000000后跟0x00007fff67a361b0

IOW,在第一个版本中,您的堆栈看起来像

 Item        Address            00  01  02  03  04  05  06  07   
 ----        -------            --  --  --  --  --  --  --  --
    j        0x8000             00  00  00  00  00  00  00  00
    i        0x8008             00  00  7f  ff  67  a3  61  b0

而在第二个版本中,它看起来像

 Item        Address            00  01  02  03  04  05  06  07   
 ----        -------            --  --  --  --  --  --  --  --
    i        0x8000             00  00  00  00  00  00  00  00
             0x8008             ??  ??  ??  ??  ??  ??  ??  ??

(地址值仅用于说明,并不对应任何真实架构)。

对于傻笑,将打印语句修改为

printf("%p: %p\n", &i, i);
printf("%p: %p\n", &j, j);

在第一个版本和

printf("%p: %p\n", &i, i);

在第二。我敢打赌,在第二个版本中为(&i变量的地址)打印的值将与在第一个版本中为(变量的地址)i打印的值相同。 &jj

注意- 这与 C语言无关,与您的特定实现(编译器、链接器等)有关。我不相信您正在调用未定义的行为(您没有通过那些无效指针访问任何内存),但是您看到了不显式初始化指针值的危险。

在没有关键字的块范围内声明的变量不会static被初始化;实例化变量时内存中的任何内容都是初始值,并且该位模式可能不代表该类型的有效值(这称为陷阱表示)。在文件范围(任何函数之外)或使用static关键字声明的变量初始化为 0 或 NULL,具体取决于它是标量类型还是指针类型。聚合类型(数组、结构和联合)的规则稍微复杂一些,但基本原理是相同的。

于 2013-03-12T17:29:47.380 回答
0

staticC 只会自动将全局变量(全局变量在函数外部声明)初始化为零。 自动变量(这就是您的两个指针所调用的)不会自动初始化,因此您正在打印“堆栈噪音”(即,当您的函数初始化时,堆栈上发生的任何值。打印的值甚至可能在运行之间发生变化你的程序。如果你想让它们被初始化,NULL你需要告诉编译器:

int *i = NULL;
int *j = NULL;
于 2013-03-12T16:26:36.363 回答
0

“未初始化”与“初始化为 0”(或 NULL)非常不同。

变量ij未初始化。他们留下了记忆中的东西。

当您注释掉第二个printf时,变量j不再使用。它可能已被编译器优化(意味着根本没有定义)。在这种情况下,i可能在不同的位置,具有不同的未初始化值。

这实际上是未定义的行为。我的最后一部分是纯粹的猜测,你永远无法确定。

于 2013-03-12T16:23:23.713 回答
0

指针可以容纳任何东西。C 不会初始化本地(自动)变量,除非您告诉它这样做。如果您将它们定义为静态,它们将被初始化为 NULL。

此外,您应该使用%p打印指针,而不是%d.

于 2013-03-12T16:24:34.037 回答
0

如果您不初始化指针地址,您将获得未定义的行为

在这里,您将指针地址打印为 int ,这是不正确的,您应该使用"%p" 而不是"%d"

于 2013-03-12T16:25:04.487 回答
0

And, how does C initialize pointers?

C没有,你做。

As far as I know, if a pointer is not initialized, it would have value Null which is equal to 0, correct?

错误的。如果它没有被初始化,它就没有定义的值。会是垃圾。打印未初始化的变量将导致垃圾,这就是您无法预期输出的原因。

Why in the first output, the i was initialized?

不是,它只是碰巧指向 0。

旁注:%p打印指针时应该使用。

于 2013-03-12T16:25:33.173 回答