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

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

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

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

P.S.

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


当前回答

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

例如:

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;
}

其他回答

指针是一种在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.

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

Come to think about it, I think it's a matter of semantics. I don't think the author is right, since the C standard refers to a pointer as holding an address to the referenced object as others have already mentioned here. However, address!=memory address. An address can be really anything as per C standard although it will eventually lead to a memory address, the pointer itself can be an id, an offset + selector (x86), really anything as long as it can describe (after mapping) any memory address in the addressable space.

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

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

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

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

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

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

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