在关于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*操作值是可能的(尽管不是很可移植)。

其他回答

马克·贝西(Mark Bessey)已经说过了,但这一点需要再次强调,直到人们理解为止。

指针与变量的关系比与文字3的关系更大。

指针是一个值(地址)和类型(带有其他属性,如只读)的元组。类型(以及附加参数(如果有的话)可以进一步定义或限制上下文;如。__far ptr, __near ptr:地址的上下文是什么:堆栈,堆,线性地址,某处的偏移量,物理内存或其他。

正是type的属性使得指针算术与整数算术略有不同。

指针不是变量的反例太多了,不容忽视

fopen返回FILE指针。(变量在哪里) 堆栈指针或帧指针通常是不可寻址的寄存器 *(int *)0x1231330 = 13;——将任意整数值转换为pointer_of_integer类型,并在不引入变量的情况下写入/读取整数值

在c程序的生命周期中,会有许多其他没有地址的临时指针实例——因此它们不是变量,而是带有编译时相关类型的表达式/值。

地址用于标识一个固定大小的存储空间,通常为每个字节,作为一个整数。这被精确地称为字节地址,它也被ISO c使用。可以有一些其他方法来构造地址,例如为每一位。然而,只有字节地址是如此经常使用,我们通常省略“字节”。

从技术上讲,一个地址在C中从来都不是一个值,因为在(ISO) C中术语“值”的定义是:

对象的内容在解释为具有特定类型时的精确含义

(我强调了一下。)然而,在C语言中没有这样的“地址类型”。

指针不一样。指针是C语言中的一种类型。有几种不同的指针类型。它们不一定遵守相同的语言规则集,例如++对int*类型值和char*类型值的影响。

C语言中的值可以是指针类型。这叫做指针值。需要明确的是,指针值在C语言中不是指针。但是我们习惯把它们混在一起,因为在C语言中,它不太可能是模棱两可的:如果我们把表达式p称为“指针”,它只是一个指针值,而不是一个类型,因为C语言中的命名类型不是由表达式表示,而是由type-name或typedef-name表示。

其他一些事情是微妙的。作为C语言的使用者,首先要知道object是什么意思:

数据存储在执行环境中的区域,其中的内容可以表示 值

对象是表示特定类型的值的实体。指针是一种对象类型。因此,如果我们声明int* p;,则p表示“指针类型的对象”,或“指针对象”。

Note there is no "variable" normatively defined by the standard (in fact it is never being used as a noun by ISO C in normative text). However, informally, we call an object a variable, as some other language does. (But still not so exactly, e.g. in C++ a variable can be of reference type normatively, which is not an object.) The phrases "pointer object" or "pointer variable" are sometimes treated like "pointer value" as above, with a probable slight difference. (One more set of examples is "array".)

由于指针是一种类型,而地址在C语言中实际上是“无类型的”,因此指针值大致“包含”一个地址。指针类型的表达式可以产生一个地址,例如。

Iso c11 6.5.2.3

一元&操作符产生其操作数的地址。

请注意,这个措辞是由WG14/N1256引入的,即ISO C99:TC3。在C99中有

一元&操作符返回其操作数的地址。

它反映了委员会的观点:地址不是由一元操作符&返回的指针值。

尽管有上述措辞,但即使在标准上也存在一些混乱。

Iso c11 6.6

地址常量是一个空指针,一个指向左值的指针,该左值指定一个static对象 存储持续时间,或指向函数指示符的指针

Iso c++ 11 5.19

3.一个地址 常量表达式是指针类型的prvalue核心常量表达式,计算结果为对象的地址 具有静态存储持续时间的对象,转换为函数的地址、空指针值或prvalue核心 类型std::nullptr_t. ...的常量表达式

(最近的c++标准草案使用了另一种措辞,所以不存在这个问题。)

实际上,C中的“地址常量”和c++中的“地址常量表达式”都是指针类型的常量表达式(或者至少从c++ 11开始是“类指针”类型)。

内置的一元&运算符在C和c++中被称为“address-of”;类似地,std::addressof是在c++ 11中引入的。

这些命名可能会带来误解。结果表达式是指针类型的,所以它们被解释为:结果包含/产生一个地址,而不是一个地址。

在理解指针之前,我们需要先理解对象。对象是存在的实体,具有一个称为地址的位置说明符。指针与C语言中的其他变量一样,是一个类型为指针的变量,其内容被解释为支持以下操作的对象的地址。

+ : A variable of type integer (usually called offset) can be added to yield a new pointer
- : A variable of type integer (usually called offset) can be subtracted to yield a new pointer
  : A variable of type pointer can be subtracted to yield an integer (usually called offset)
* : De-referencing. Retrieve the value of the variable (called address) and map to the object the address refers to.
++: It's just `+= 1`
--: It's just `-= 1`

指针是根据它当前引用的对象类型进行分类的。唯一重要的信息是物体的大小。

任何对象都支持& (address of)操作,该操作将对象的位置说明符(地址)作为指针对象类型检索。这将减少围绕命名的混乱,因为调用&作为对象的操作而不是作为结果类型为对象类型的指针的指针是有意义的。

注意:在整个解释中,我省略了内存的概念。

以下是我过去是如何向一些困惑的人解释的: 指针有两个影响其行为的属性。它有一个值(在典型环境中)是一个内存地址,还有一个类型(告诉您它所指向的对象的类型和大小)。

例如,给定:

union {
    int i;
    char c;
} u;

你可以有三个不同的指针都指向同一个对象:

void *v = &u;
int *i = &u.i;
char *c = &u.c;

如果你比较这些指针的值,它们都是相等的:

v==i && i==c

但是,如果对每个指针加1,就会发现它们所指向的类型变得相关了。

i++;
c++;
// You can't perform arithmetic on a void pointer, so no v++
i != c

此时,变量i和c将具有不同的值,因为i++使i包含下一个可访问的整数的地址,而c++使c指向下一个可寻址的字符。通常,整数比字符占用更多的内存,所以在它们都加一之后,i的值将比c的值更大。

简单地说,指针实际上是分割机制的偏移部分,分割后转换为线性地址,分页后转换为物理地址。物理地址实际上是从ram中寻址的。

       Selector  +--------------+         +-----------+
      ---------->|              |         |           |
                 | Segmentation | ------->|  Paging   |
        Offset   |  Mechanism   |         | Mechanism |
      ---------->|              |         |           |
                 +--------------+         +-----------+
        Virtual                   Linear                Physical