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

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

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

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

P.S.

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


当前回答

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

其他回答

在理解指针之前,我们需要先理解对象。对象是存在的实体,具有一个称为地址的位置说明符。指针与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)操作,该操作将对象的位置说明符(地址)作为指针对象类型检索。这将减少围绕命名的混乱,因为调用&作为对象的操作而不是作为结果类型为对象类型的指针的指针是有意义的。

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

你是对的,是理智的。通常,指针只是一个地址,因此您可以将其强制转换为整数并进行任何算术运算。

但有时指针只是地址的一部分。在一些体系结构上,指针被转换为一个增加了基数的地址或使用另一个CPU寄存器。

但是现在,在PC和ARM架构上,使用平面内存模型和原生编译的C语言,可以认为指针是指向一维可寻址RAM中某个位置的整数地址。

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

A pointer, like any other variable in C, is fundamentally a collection of bits which may be represented by one or more concatenated unsigned char values (as with any other type of cariable, sizeof(some_variable) will indicate the number of unsigned char values). What makes a pointer different from other variables is that a C compiler will interpret the bits in a pointer as identifying, somehow, a place where a variable may be stored. In C, unlike some other languages, it is possible to request space for multiple variables, and then convert a pointer to any value in that set into a pointer to any other variable within that set.

Many compilers implement pointers by using their bits store actual machine addresses, but that is not the only possible implementation. An implementation could keep one array--not accessible to user code--listing the hardware address and allocated size of all of the memory objects (sets of variables) which a program was using, and have each pointer contain an index into an array along with an offset from that index. Such a design would allow a system to not only restrict code to only operating upon memory that it owned, but also ensure that a pointer to one memory item could not be accidentally converted into a pointer to another memory item (in a system that uses hardware addresses, if foo and bar are arrays of 10 items that are stored consecutively in memory, a pointer to the "eleventh" item of foo might instead point to the first item of bar, but in a system where each "pointer" is an object ID and an offset, the system could trap if code tried to index a pointer to foo beyond its allocated range). It would also be possible for such a system to eliminate memory-fragmentation problems, since the physical addresses associated with any pointers could be moved around.

Note that while pointers are somewhat abstract, they're not quite abstract enough to allow a fully-standards-compliant C compiler to implement a garbage collector. The C compiler specifies that every variable, including pointers, is represented as a sequence of unsigned char values. Given any variable, one can decompose it into a sequence of numbers and later convert that sequence of numbers back into a variable of the original type. Consequently, it would be possible for a program to calloc some storage (receiving a pointer to it), store something there, decompose the pointer into a series of bytes, display those on the screen, and then erase all reference to them. If the program then accepted some numbers from the keyboard, reconstituted those to a pointer, and then tried to read data from that pointer, and if user entered the same numbers that the program had earlier displayed, the program would be required to output the data that had been stored in the calloc'ed memory. Since there is no conceivable way the computer could know whether the user had made a copy of the numbers that were displayed, there would be no conceivable may the computer could know whether the aforementioned memory might ever be accessed in future.

在这幅图中,

Pointer_p是一个位于0x12345的指针,它指向0x34567的变量variable_v。