在关于C的一个有信誉的来源中,在讨论&操作符后给出了以下信息:

... 有点不幸的是,术语[地址的]仍然存在,因为它混淆了那些不知道地址是关于什么的人,并误导了那些知道地址的人:将指针视为地址通常会导致悲伤……

我读过的其他材料(来自同样有名望的来源,我想说)总是毫不掩饰地将指针和&操作符作为内存地址。我很愿意继续寻找事情的真相,但当有信誉的消息来源不同意时,这有点困难。

现在我有点困惑了——如果指针不是内存地址,那么它到底是什么?

P.S.

作者后来说:……不过,我将继续使用“地址”这个术语,因为发明一个不同的(术语)会更糟糕。


当前回答

它说“因为它让那些不知道地址是什么的人感到困惑”——而且,这是真的:如果你知道地址是什么,你就不会困惑了。从理论上讲,指针是一个指向另一个变量的变量,实际上保存着一个地址,即它所指向的变量的地址。我不知道为什么要隐瞒这个事实,这又不是什么高深的科学。如果你理解了指针,你就离理解计算机的工作原理更近了一步。去吧!

其他回答

C或c++指针与简单内存地址的另一个不同之处是,我在其他答案中没有看到不同的指针类型(尽管考虑到它们的总大小,我可能忽略了它)。但它可能是最重要的一个,因为即使是经验丰富的C/ c++程序员也会被它绊倒:

编译器可能会假设不兼容类型的指针不指向相同的地址,即使它们很明显指向相同的地址,这可能会导致简单的pointer==address模型不可能出现的行为。考虑以下代码(假设sizeof(int) = 2*sizeof(short)):

unsigned int i = 0;
unsigned short* p = (unsigned short*)&i;
p[0]=p[1]=1;

if (i == 2 + (unsigned short)(-1))
{
  // you'd expect this to execute, but it need not
}

if (i == 0)
{
  // you'd expect this not to execute, but it actually may do so
}

注意,char*有一个例外,所以使用char*操作值是可能的(尽管不是很可移植)。

指针是一种在C/ c++中本地可用的变量类型,包含一个内存地址。像任何其他变量一样,它有自己的地址并占用内存(数量是特定于平台的)。

由于混淆,您将看到的一个问题是试图通过简单地按值传递指针来更改函数中的引用。这将复制函数作用域内的指针,对这个新指针“指向”的地方的任何更改都不会改变调用该函数的作用域内指针的引用。为了修改函数中的实际指针,通常会将一个指针传递给另一个指针。

把指针看作地址是一种近似。像所有的近似值一样,它有时足够有用,但也不准确,这意味着依赖它会带来麻烦。

指针就像一个地址,它指出在哪里可以找到一个对象。这种类比的一个直接限制是,并非所有指针都实际包含地址。NULL是一个指针,它不是地址。指针变量的内容实际上可以是以下三种类型之一:

对象的地址,可以被解引用(如果p包含x的地址,则表达式*p与x的值相同); 一个空指针,null是一个例子; 无效内容,不指向对象(如果p不持有有效值,则*p可以做任何事情(“未定义行为”),导致程序崩溃是相当常见的可能性)。

此外,更准确的说法是,一个指针(如果有效且非空)包含一个地址:指针指出在哪里可以找到一个对象,但还有更多与之相关的信息。

In particular, a pointer has a type. On most platforms, the type of the pointer has no influence at runtime, but it has an influence that goes beyond the type at compile time. If p is a pointer to int (int *p;), then p + 1 points to an integer which is sizeof(int) bytes after p (assuming p + 1 is still a valid pointer). If q is a pointer to char that points to the same address as p (char *q = p;), then q + 1 is not the same address as p + 1. If you think of pointer as addresses, it is not very intuitive that the “next address” is different for different pointers to the same location.

It is possible in some environments to have multiple pointer values with different representations (different bit patterns in memory) that point to the same location in memory. You can think of these as different pointers holding the same address, or as different addresses for the same location — the metaphor isn't clear in this case. The == operator always tells you whether the two operands are pointing to the same location, so on these environments you can have p == q even though p and q have different bit patterns.

甚至在某些环境中,指针携带除地址以外的其他信息,例如类型或权限信息。作为一名程序员,你很容易在生活中不会遇到这些问题。

在某些环境中,不同类型的指针具有不同的表示形式。你可以把它想象成不同类型的地址有不同的表示。例如,一些体系结构有字节指针和字指针,或者对象指针和函数指针。

总而言之,只要记住这一点,将指针视为地址并不太糟糕

它只有有效的,非空的地址指针; 同一个位置可以有多个地址; 你不能对地址进行算术运算,地址上也没有顺序; 指针还携带类型信息。

反过来就麻烦多了。并不是所有看起来像地址的东西都可以是指针。在深层的某个地方,任何指针都表示为可以作为整数读取的位模式,并且您可以说这个整数是一个地址。但反过来说,不是每个整数都是指针。

首先有一些众所周知的限制;例如,在程序地址空间之外指定位置的整数不能是有效指针。未对齐的地址不能为需要对齐的数据类型创建有效指针;例如,在int需要4字节对齐的平台上,0x7654321不能是有效的int*值。

然而,它远远不止于此,因为当您将指针设置为整数时,您就会遇到很多麻烦。这个问题的很大一部分是优化编译器在微优化方面比大多数程序员预期的要好得多,因此他们对程序如何工作的思维模型是严重错误的。仅仅因为指针具有相同的地址并不意味着它们是等价的。例如,考虑下面的代码片段:

unsigned int x = 0;
unsigned short *p = (unsigned short*)&x;
p[0] = 1;
printf("%u = %u\n", x, *p);

您可能会期望,在sizeof(int)==4和sizeof(short)==2的普通机器上,这要么打印1 = 1?(little-endian)还是65536 = 1?(大端)。但在我的64位Linux PC上,GCC 4.4:

$ c99 -O2 -Wall a.c && ./a.out 
a.c: In function ‘main’:
a.c:6: warning: dereferencing pointer ‘p’ does break strict-aliasing rules
a.c:5: note: initialized from here
0 = 1?

在这个简单的例子中,GCC会提醒我们哪里出了问题——在更复杂的例子中,编译器可能不会注意到。由于p与&x的类型不同,改变p指向的对象不会影响&x指向的对象(除了一些定义良好的异常)。因此,编译器可以自由地将x的值保存在寄存器中,而不会在*p更改时更新该寄存器。程序解引用两个指向相同地址的指针,得到两个不同的值!

The moral of this example is that thinking of a (non-null valid) pointer as an address is fine, as long as you stay within the precise rules of the C language. The flip side of the coin is that the rules of the C language are intricate, and difficult to get an intuitive feeling for unless you know what happens under the hood. And what happens under the hood is that the tie between pointers and addresses is somewhat loose, both to support “exotic” processor architectures and to support optimizing compilers.

因此,可以将指针作为地址作为理解的第一步,但不要过于遵循这种直觉。

指针只是另一个变量,用来保存内存位置的地址(通常是另一个变量的内存地址)。

指针是一个保存内存地址的变量,而不是地址本身。但是,您可以解除对指针的引用-并访问内存位置。

例如:

int q = 10; /*say q is at address 0x10203040*/
int *p = &q; /*means let p contain the address of q, which is 0x10203040*/
*p = 20; /*set whatever is at the address pointed by "p" as 20*/

就是这样。就是这么简单。

一个演示我所说内容的程序,其输出如下:

http://ideone.com/rcSUsb

程序:

#include <stdio.h>

int main(int argc, char *argv[])
{
  /* POINTER AS AN ADDRESS */
  int q = 10;
  int *p = &q;

  printf("address of q is %p\n", (void *)&q);
  printf("p contains %p\n", (void *)p);

  p = NULL;
  printf("NULL p now contains %p\n", (void *)p);
  return 0;
}