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

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

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

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

P.S.

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


当前回答

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

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

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

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

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

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

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

其他回答

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.

C标准没有在内部定义指针是什么以及它在内部是如何工作的。这样做的目的是为了不限制平台的数量,在这些平台上,C可以作为编译或解释语言实现。

指针值可以是某种ID或句柄,也可以是几个ID的组合(对x86段和偏移量说你好),不一定是真正的内存地址。这个ID可以是任何东西,甚至是固定大小的文本字符串。非地址表示可能对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;
}

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指针之间有很多语义上的区别。

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

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

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

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

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

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

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