在关于C的一个有信誉的来源中,在讨论&操作符后给出了以下信息:
... 有点不幸的是,术语[地址的]仍然存在,因为它混淆了那些不知道地址是关于什么的人,并误导了那些知道地址的人:将指针视为地址通常会导致悲伤……
我读过的其他材料(来自同样有名望的来源,我想说)总是毫不掩饰地将指针和&操作符作为内存地址。我很愿意继续寻找事情的真相,但当有信誉的消息来源不同意时,这有点困难。
现在我有点困惑了——如果指针不是内存地址,那么它到底是什么?
P.S.
作者后来说:……不过,我将继续使用“地址”这个术语,因为发明一个不同的(术语)会更糟糕。
C指针非常类似于内存地址,但是抽象了与机器相关的细节,以及一些在低级指令集中找不到的特性。
例如,C指针是相对丰富的类型。如果在一个结构数组中增加一个指针,它会很好地从一个结构跳到另一个结构。
指针服从转换规则,并提供编译时类型检查。
有一个特殊的“空指针”值,它在源代码级别是可移植的,但其表示可能不同。如果将值为0的整型常量赋给指针,则该指针的值为空指针。同样,如果你用这种方式初始化一个指针。
指针可以用作布尔变量:如果指针不是null,则为true;如果指针为null,则为false。
在机器语言中,如果空指针是一个有趣的地址,如0xFFFFFFFF,那么您可能必须对该值进行显式测试。C把它藏起来了。即使空指针是0xFFFFFFFF,你也可以使用if (ptr != 0) {/* not null!* /}。
Uses of pointers which subvert the type system lead to undefined behavior, whereas similar code in machine language might be well defined. Assemblers will assemble the instructions you have written, but C compilers will optimize based on the assumption that you haven't done anything wrong. If a float *p pointer points to a long n variable, and *p = 0.0 is executed, the compiler is not required to handle this. A subsequent use of n will not necessary read the bit pattern of the float value, but perhaps, it will be an optimized access which is based on the "strict aliasing" assumption that n has not been touched! That is, the assumption that the program is well-behaved, and so p should not be pointing at n.
在C语言中,指向代码的指针和指向数据的指针是不同的,但在许多体系结构中,它们的地址是相同的。可以开发具有“胖”指针的C编译器,即使目标体系结构没有。胖指针意味着指针不仅仅是机器地址,还包含其他信息,例如用于边界检查的被指向对象的大小信息。可移植编写的程序将很容易移植到这样的编译器。
所以你可以看到,在机器地址和C指针之间有很多语义上的区别。
指针是表示内存位置的抽象。请注意,这句话并没有说把指针当作内存地址是错误的,它只是说它“通常会导致悲伤”。换句话说,它会让你产生错误的期望。
The most likely source of grief is certainly pointer arithmetic, which is actually one of C's strengths. If a pointer was an address, you'd expect pointer arithmetic to be address arithmetic; but it's not. For example, adding 10 to an address should give you an address that is larger by 10 addressing units; but adding 10 to a pointer increments it by 10 times the size of the kind of object it points to (and not even the actual size, but rounded up to an alignment boundary). With an int * on an ordinary architecture with 32-bit integers, adding 10 to it would increment it by 40 addressing units (bytes). Experienced C programmers are aware of this and put it to all kinds of good uses, but your author is evidently no fan of sloppy metaphors.
There's the additional question of how the contents of the pointer represent the memory location: As many of the answers have explained, an address is not always an int (or long). In some architectures an address is a "segment" plus an offset. A pointer might even contain just the offset into the current segment ("near" pointer), which by itself is not a unique memory address. And the pointer contents might have only an indirect relationship to a memory address as the hardware understands it. But the author of the quote cited doesn't even mention representation, so I think it was conceptual equivalence, rather than representation, that they had in mind.
C指针非常类似于内存地址,但是抽象了与机器相关的细节,以及一些在低级指令集中找不到的特性。
例如,C指针是相对丰富的类型。如果在一个结构数组中增加一个指针,它会很好地从一个结构跳到另一个结构。
指针服从转换规则,并提供编译时类型检查。
有一个特殊的“空指针”值,它在源代码级别是可移植的,但其表示可能不同。如果将值为0的整型常量赋给指针,则该指针的值为空指针。同样,如果你用这种方式初始化一个指针。
指针可以用作布尔变量:如果指针不是null,则为true;如果指针为null,则为false。
在机器语言中,如果空指针是一个有趣的地址,如0xFFFFFFFF,那么您可能必须对该值进行显式测试。C把它藏起来了。即使空指针是0xFFFFFFFF,你也可以使用if (ptr != 0) {/* not null!* /}。
Uses of pointers which subvert the type system lead to undefined behavior, whereas similar code in machine language might be well defined. Assemblers will assemble the instructions you have written, but C compilers will optimize based on the assumption that you haven't done anything wrong. If a float *p pointer points to a long n variable, and *p = 0.0 is executed, the compiler is not required to handle this. A subsequent use of n will not necessary read the bit pattern of the float value, but perhaps, it will be an optimized access which is based on the "strict aliasing" assumption that n has not been touched! That is, the assumption that the program is well-behaved, and so p should not be pointing at n.
在C语言中,指向代码的指针和指向数据的指针是不同的,但在许多体系结构中,它们的地址是相同的。可以开发具有“胖”指针的C编译器,即使目标体系结构没有。胖指针意味着指针不仅仅是机器地址,还包含其他信息,例如用于边界检查的被指向对象的大小信息。可移植编写的程序将很容易移植到这样的编译器。
所以你可以看到,在机器地址和C指针之间有很多语义上的区别。
指针是一个保存内存地址的变量,而不是地址本身。但是,您可以解除对指针的引用-并访问内存位置。
例如:
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;
}