In a reputable source about C, the following information is given after discussing the &
operator:
... It's a bit unfortunate that the terminology [address of] remains, because it confuses those who don't know what addresses are about, and misleads those who do: thinking about pointers as if they were addresses usually leads to grief...
Other materials I have read (from equally reputable sources, I would say) have always unabashedly referred to pointers and the &
operator as giving memory addresses. I would love to keep searching for the actuality of the matter, but it is kind of difficult when reputable sources KIND OF disagree.
Now I am slightly confused--what exactly is a pointer, then, if not a memory address?
P.S.
The author later says: ...I will continue to use the term 'address of' though, because to invent a different one [term] would be even worse.
The C standard does not define what a pointer is internally and how it works internally. This is intentional so as not to limit the number of platforms, where C can be implemented as a compiled or interpreted language.
A pointer value can be some kind of ID or handle or a combination of several IDs (say hello to x86 segments and offsets) and not necessarily a real memory address. This ID could be anything, even a fixed-size text string. Non-address representations may be especially useful for a C interpreter.
I'm not sure about your source, but the type of language you're describing comes from the C standard:
So... yeah, pointers point to memory addresses. At least that's how the C standard suggests it to mean.
To say it a bit more clearly, a pointer is a variable holding the value of some address. The address of an object (which may be stored in a pointer) is returned with the unary
&
operator.I can store the address "42 Wallaby Way, Sydney" in a variable (and that variable would be a "pointer" of sorts, but since that's not a memory address it's not something we'd properly call a "pointer"). Your computer has addresses for its buckets of memory. Pointers store the value of an address (i.e. a pointer stores the value "42 Wallaby Way, Sydney", which is an address).
Edit: I want to expand on Alexey Frunze's comment.
What exactly is a pointer? Let's look at the C standard:
Essentially, pointers store a value that provides a reference to some object or function. Kind of. Pointers are intended to store a value that provides a reference to some object or function, but that's not always the case:
The above quote says that we can turn an integer into a pointer. If we do that (that is, if we stuff an integer value into a pointer instead of a specific reference to an object or function), then the pointer "might not point to an entity of reference type" (i.e. it may not provide a reference to an object or function). It might provide us with something else. And this is one place where you might stick some kind of handle or ID in a pointer (i.e. the pointer isn't pointing to an object; it's storing a value that represents something, but that value may not be an address).
So yes, as Alexey Frunze says, it's possible a pointer isn't storing an address to an object or function. It's possible a pointer is instead storing some kind of "handle" or ID, and you can do this by assigning some arbitrary integer value to a pointer. What this handle or ID represents depends on the system/environment/context. So long as your system/implementation can make sense of the value, you're in good shape (but that depends on the specific value and the specific system/implemenation).
Normally, a pointer stores an address to an object or function. If it isn't storing an actual address (to an object or function), the result is implementation defined (meaning that exactly what happens and what the pointer now represents depends on your system and implementation, so it might be a handle or ID on a particular system, but using the same code/value on another system might crash your program).
That ended up being longer than I thought it would be...
In this picture,
pointer_p is a pointer which is located at 0x12345, and is pointing to a variable variable_v at 0x34567.
To think of a pointer as an address is an approximation. Like all approximations, it's good enough to be useful sometimes, but it's also not exact which means that relying on it causes trouble.
A pointer is like an address in that it indicates where to find an object. One immediate limitation of this analogy is that not all pointers actually contain an address.
NULL
is a pointer which is not an address. The content of a pointer variable can in fact be of one of three kinds:p
contains the address ofx
then the expression*p
has the same value asx
);NULL
is an example;p
doesn't hold a valid value, then*p
could do anything (“undefined behavior”), with crashing the program a fairly common possibility).Furthermore, it would be more accurate to say that a pointer (if valid and non-null) contains an address: a pointer indicates where to find an object, but there is more information tied to it.
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 toint
(int *p;
), thenp + 1
points to an integer which issizeof(int)
bytes afterp
(assumingp + 1
is still a valid pointer). Ifq
is a pointer tochar
that points to the same address asp
(char *q = p;
), thenq + 1
is not the same address asp + 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 havep == q
even thoughp
andq
have different bit patterns.There are even environments where pointers carry other information beyond the address, such as type or permission information. You can easily go through your life as a programmer without encountering these.
There are environments where different kinds of pointers have different representations. You can think of it as different kinds of addresses having different representations. For example, some architectures have byte pointers and word pointers, or object pointers and function pointers.
All in all, thinking of pointers as addresses isn't too bad as long as you keep in mind that
Going the other way round is far more troublesome. Not everything that looks like an address can be a pointer. Somewhere deep down any pointer is represented as a bit pattern that can be read as an integer, and you can say that this integer is an address. But going the other way, not every integer is a pointer.
There are first some well-known limitations; for example, an integer that designates a location outside your program's address space can't be a valid pointer. A misaligned address doesn't make a valid pointer for a data type that requires alignment; for example, on a platform where
int
requires 4-byte alignment, 0x7654321 cannot be a validint*
value.However, it goes well beyond that, because when you make a pointer into an integer, you're in for a world of trouble. A big part of this trouble is that optimizing compilers are far better at microoptimization than most programmers expect, so that their mental model of how a program works is deeply wrong. Just because you have pointers with the same address doesn't mean that they are equivalent. For example, consider the following snippet:
You might expect that on a run-of-the-mill machine where
sizeof(int)==4
andsizeof(short)==2
, this either prints1 = 1?
(little-endian) or65536 = 1?
(big-endian). But on my 64-bit Linux PC with GCC 4.4:GCC is kind enough to warn us what's going wrong in this simple example — in more complex examples, the compiler might not notice. Since
p
has a different type from&x
, changing whatp
points to cannot affect what&x
points to (outside some well-defined exceptions). Therefore the compiler is at liberty to keep the value ofx
in a register and not update this register as*p
changes. The program dereferences two pointers to the same address and obtains two different values!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.
So think of pointers being addresses as a first step in your understanding, but don't follow that intuition too far.
A pointer is a variable that HOLDS memory address, not the address itself. However, you can dereference a pointer - and get access to the memory location.
For example:
That's it. It's that simple.
A program to demonstrate what I am saying and its output is here:
http://ideone.com/rcSUsb
The program:
It's difficult to tell exactly what the authors of those books mean exactly. Whether a pointer contains an address or not depends on how you define an address and how you define a pointer.
Judging from all the answers that are written, some people assume that (1) an address must be an integer and (2) a pointer doesn't need to be by virtual of not being said so in the specification. With these assumptions, then clearly pointers do not necessarily contain addresses.
However, we see that while (2) is probably true, (1) probably doesn't have to be true. And what to make of the fact that the & is called the address of operator as per @CornStalks's answer? Does this mean that the authors of the specification intend for a pointer to contain an address?
So can we say, pointer contains an address, but an address doesn't have to be an integer? Maybe.
I think all of this is jibberish pedantic semantic talk. It is totally worthless practically speaking. Can you think of a compiler that generates code in such a way that the value of a pointer is not an address? If so, what? That's what I thought...
I think what the author of the book (the first excerpt that claims that pointers are not necessarily just addresses) probably is referring to is the fact that a pointer comes with it the inherent type information.
For example,
both y and z are pointers, but y+1 and z+1 are different. if they are memory addresses, wouldn't those expressions give you the same value?
And here in lies the thinking about pointers as if they were addresses usually leads to grief. Bugs have been written because people think about pointers as if they were addresses, and this usually leads to grief.
55555 is probably not a pointer, although it may be an address, but (int*)55555 is a pointer. 55555+1 = 55556, but (int*)55555+1 is 55559 (+/- difference in terms of sizeof(int)).
Well, a pointer is an abstraction representing a memory location. Note that the quote doesn't say that thinking about pointers as if they were memory addresses is wrong, it just says that it "usually leads to grief". In other words, it leads you to have incorrect expectations.
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 live with it, 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.
Here's how I've explained it to some confused people in the past: A pointer has two attributes that affect its behavior. It has a value, which is (in typical environments) a memory address, and a type, which tells you the type and size of the object that it points at.
For example, given:
You can have three different pointers all pointing to this same object:
If you compare the values of these pointers, they're all equal:
However, if you increment each pointer, you'll see that the type that they point to becomes relevant.
The variables
i
andc
will have different values at this point, becausei++
causesi
to contain the address of the next-accessible integer, andc++
causesc
to point to the next-addressable character. Typically, integers take up more memory than characters, soi
will end up with a larger value thanc
after they are both incremented.Mark Bessey already said it, but this needs to be re-emphasised until understood.
Pointer has as much to do with a variable than a literal 3.
Pointer is a tuple of a value (of an address) and a type (with additional properties, such as read only). The type (and the additional parameters if any) can further define or restrict the context; eg.
__far ptr, __near ptr
: what is the context of the address: stack, heap, linear address, offset from somewhere, physical memory or what.It's the property of type that makes pointer arithmetic a bit different to integer arithmetic.
The counter examples of a pointer of not being a variable are too many to ignore
stack pointer or frame pointer being typically unaddressable registers
*(int *)0x1231330 = 13;
-- casting an arbitrary integer value to a pointer_of_integer type and writing/reading an integer without ever introducing a variableIn the lifetime of a C-program there will be many other instances of temporary pointers that do not have addresses -- and therefore they are not variables, but expressions/values with a compile time associated type.
You are right and sane. Normally, a pointer is just an address, so you can cast it to integer and do any arithmetics.
But sometimes pointers are only a part of an address. On some architectures a pointer is converted to an address with addition of base or another CPU register is used.
But these days, on PC and ARM architecture with a flat memory model and C language natively compiled, it's OK to think that a pointer is an integer address to some place in one-dimensional addressable RAM.
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 ofunsigned 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
andbar
are arrays of 10 items that are stored consecutively in memory, a pointer to the "eleventh" item offoo
might instead point to the first item ofbar
, 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 tofoo
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 tocalloc
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 thecalloc
'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.A pointer is a variable type that is natively available in C/C++ and contains a memory address. Like any other variable it has an address of its own and takes up memory (the amount is platform specific).
One problem you will see as a result of the confusion is trying to change the referent within a function by simply passing the pointer by value. This will make a copy of the pointer at function scope and any changes to where this new pointer "points" will not change the referent of the pointer at the scope that invoked the function. In order to modify the actual pointer within a function one would normally pass a pointer to a pointer.
BRIEF SUMMARY (which I will also put at the top):
(0) Thinking of pointers as addresses is often a good learning tool, and is often the actual implementation for pointers to ordinary data types.
(1) But on many, perhaps most, compilers pointers to functions are not addresses, but are bigger than an address (typically 2x, sometimes more), or are actually pointers to a struct in memory than contains the addresses of function and stuff like a constant pool.
(2) Pointers to data members and pointers to methods are often even stranger.
(3) Legacy x86 code with FAR and NEAR pointer issues
(4) Several examples, most notably the IBM AS/400, with secure "fat pointers".
I am sure you can find more.
DETAIL:
UMMPPHHH!!!!! Many of the answers so far are fairly typical "programmer weenie" answers - but not compiler weenie or hardware weenie. Since I pretend to be a hardware weenie, and often work with compiler weenies, let me throw in my two cents:
On many, probably most, C compilers, a pointer to data of type
T
is, in fact, the address ofT
.Fine.
But, even on many of these compilers, certain pointers are NOT addresses. You can tell this by looking at
sizeof(ThePointer)
.For example, pointers to functions are sometimes quite a lot bigger than ordinary addresses. Or, they may involve a level of indirection. This article provides one description, involving the Intel Itanium processor, but I have seen others. Typically, to call a function you must know not only the address of the function code, but also the address of the function's constant pool - a region of memory from which constants are loaded with a single load instruction, rather than the compiler having to generate a 64 bit constant out of several Load Immediate and Shift and OR instructions. So, rather than a single 64 bit address, you need 2 64 bit addresses. Some ABIs (Application Binary Interfaces) move this around as 128 bits, whereas others use a level of indirection, with the function pointer actually being the address of a function descriptor that contains the 2 actual addresses just mentioned. Which is better? Depends on your point of view: performance, code size, and some compatibility issues - often code assumes that a pointer can be cast to a long or a long long, but may also assume that the long long is exactly 64 bits. Such code may not be standards compliant, but nevertheless customers may want it to work.
Many of us have painful memories of the old Intel x86 segmented architecture, with NEAR POINTERs and FAR POINTERS. Thankfully these are nearly extinct by now, so only a quick summary: in 16 bit real mode, the actual linear address was
Whereas in protected mode, it might be
with the resulting address being checked against a limit set in the segment. Some programs used not really standard C/C++ FAR and NEAR pointer declarations, but many just said
*T
--- but there were compiler and linker switches so, for example, code pointers might be near pointers, just a 32 bit offset against whatever is in the CS (Code Segment) register, while the data pointers might be FAR pointers, specifying both a 16 bit segment number and a 32 bit offset for a 48 bit value. Now, both of these quantities are certainly related to the address, but since they aren't the same size, which of them is the address? Moreover, the segments also carried permissions - read-only, read-write, executable - in addition to stuff related to the actual address.A more interesting example, IMHO, is (or, perhaps, was) the IBM AS/400 family. This computer was one of the first to implement an OS in C++. Pointers on this machime were typically 2X the actual address size - e.g. as this presentation says, 128 bit pointers, but the actual addresses were 48-64 bits, and, again, some extra info, what is called a capability, that provided permissions such as read, write, as well as a limit to prevent buffer overflow. Yes: you can do this compatibly with C/C++ -- and if this were ubiquitous, the Chinese PLA and slavic mafia would not be hacking into so many Western computer systems. But historically most C/C++ programming has neglected security for performance. Most interestingly, the AS400 family allowed the operating system to create secure pointers, that could be given to unprivileged code, but which the unprivileged code could not forge or tamper with. Again, security, and while standards compliant, much sloppy non-standards compliant C/C++ code will not work in such a secure system. Again, there are official standards, and there are de-facto standards.
Now, I'll get off my security soapbox, and mention some other ways in which pointers (of various types) are often not really addresses: Pointers to data members, pointers to member functions methods, and the static versions thereof are bigger than an ordinary address. As this post says:
As you can probably guess from my pontificating on (in)security, I've been involved in C/C++ hardware/software projects where a pointer was treated more like a capability than a raw address.
I could go on, but I hope you get the idea.
BRIEF SUMMARY (which I will also put at the top):
(0) thinking of pointers as addresses is often a good learning tool, and is often the actual implementation for pointers to ordinary data types.
(1) But on many, perhaps most, compilers pointers to functions are not addresses, but are bigger than an address (typically 2X, sometimes more), or are actually pointers to a struct in memory than contains the addresses of function and stuff like a constant pool.
(2) Pointers to data members and pointers to methods are often even stranger.
(3) Legacy x86 code with FAR and NEAR pointer issues
(4) Several examples, most notably the IBM AS/400, with secure "fat pointers".
I am sure you can find more.
A pointer is just another variable which is used to hold the address of a memory location (usually the memory address of another variable).
You can see it this way. A pointer is a value that represents an address in the addressable memory space.
A pointer is just another variable that can contain memory address usually of another variable. A pointer being a variable it too has an memory address.
A C pointer is very similar to a memory address but with machine-dependent details abstracted away, as well as some features not found in the lower level instruction set.
For example, a C pointer is relatively richly typed. If you increment a pointer through an array of structures, it nicely jumps from one structure to the other.
Pointers are subject to conversion rules and provide compile time type checking.
There is a special "null pointer" value which is portable at the source code level, but whose representation may differ. If you assign an integer constant whose value is zero to a pointer, that pointer takes on the null pointer value. Ditto if you initialize a pointer that way.
A pointer can be used as a boolean variable: it tests true if it is other than null, and false if it is null.
In a machine language, if the null pointer is a funny address like 0xFFFFFFFF, then you may have to have explicit tests for that value. C hides that from you. Even if the null pointer is 0xFFFFFFFF, you can test it using
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 along n
variable, and*p = 0.0
is executed, the compiler is not required to handle this. A subsequent use ofn
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 thatn
has not been touched! That is, the assumption that the program is well-behaved, and sop
should not be pointing atn
.In C, pointers to code and pointers to data are different, but on many architectures, the addresses are the same. C compilers can be developed which have "fat" pointers, even though the target architecture does not. Fat pointers means that pointers are not just machine addresses, but contain other info, such as information about the size of the object being pointed at, for bounds checking. Portably written programs will easily port to such compilers.
So you can see, there are many semantic differences between machine addresses and C pointers.
Before understanding pointers we need to understand objects. Objects are entities which exist and has a location specifier called an address. A pointer is just a variable like any other variables in
C
with a type calledpointer
whose content is interpreted as the address of an object which supports the following operation.A pointer is classified based on the type of object it is currently referring. The only part of the information it matters is the size of the object.
Any object supports an operation,
&
(address of), which retrieves the location specifier (address) of the object as a pointer object type. This should abate the confusion surrounding the nomenclature as this would make sense to call&
as an operation of an object rather than a pointer whose resultant type is a pointer of the object type.Note Throughout this explanation, I have left out the concept of memory.
An address is used to identify a piece of fixed-size storage, usually for each bytes, as an integer. This is precisely called as byte address, which is also used by the ISO C. There can be some other methods to construct an address, e.g. for each bit. However, only byte address is so often used, we usually omit "byte".
Technically, an address is never a value in C, because the definition of term "value" in (ISO) C is:
(Emphasized by me.) However, there is no such "address type" in C.
Pointer is not the same. Pointer is a kind of type in the C language. There are several distinct pointer types. They does not necessarily obey to identical set of rules of the language, e.g. the effect of
++
on a value of typeint*
vs.char*
.A value in C can be of a pointer type. This is called a pointer value. To be clear, a pointer value is not a pointer in the C language. But we are accustomed to mix them together, because in C it is not likely to be ambiguous: if we call an expression
p
as a "pointer", it is merely a pointer value but not a type, since a named type in C is not expressed by an expression, but by a type-name or a typedef-name.Some other things are subtle. As a C user, firstly, one should know what
object
means:An object is an entity to represent values, which are of a specific type. A pointer is an object type. So if we declare
int* p;
, thenp
means "an object of pointer type", or an "pointer object".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".)
Since pointer is a type, and address is effectively "typeless" in C, a pointer value roughly "contains" an address. And an expression of pointer type can yield an address, e.g.
ISO C11 6.5.2.3
Note this wording is introduced by WG14/N1256, i.e. ISO C99:TC3. In C99 there is
It reflects the committee's opinion: an address is not a pointer value returned by the unary
&
operator.Despite the wording above, there are still some mess even in the standards.
ISO C11 6.6
ISO C++11 5.19
(Recent C++ standard draft uses another wording so there is no this problem.)
Actually both "address constant" in C and "address constant expression" in C++ are constant expression of pointer types (or at least "pointer-like" types since C++11).
And the builtin unary
&
operator is called as "address-of" in C and C++; similarily,std::addressof
is introduced in C++11.These naming may bring misconception. The resulted expression is of pointer type, so they'd be interpreted as: the result contains/yields an address, rather than is an address.
It says "because it confuses those who don't know what addresses are about" - also, it's true: if you learn what addresses are about, you'll be not confused. Theoretically, pointer is a variable which points to another, practically holds an address, which is the address of the variable it points to. I don't know why should hide this fact, it's not a rocket science. If you understand pointers, you'll one step closer to understand how computers work. Go ahead!
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.
One other way in which a C or C++ pointer differs from a simple memory address due to the different pointer types I haven't seen in the other answers (altrhough given their total size, I may have overlooked it). But it is probably the most important one, because even experienced C/C++ programmers can trip over it:
The compiler may assume that pointers of incompatible types do not point to the same address even if they clearly do, which may give behaviour that would no be possible with a simple pointer==address model. Consider the following code (assuming
sizeof(int) = 2*sizeof(short)
):Note that there's an exception for
char*
, so manipulating values usingchar*
is possible (although not very portable).Quick summary: A C address is a value, typically represented as a machine-level memory address, with a specific type.
The unqualified word "pointer" is ambiguous. C has pointer objects (variables), pointer types, pointer expressions, and pointer values.
It's very common to use the word "pointer" to mean "pointer object", and that can lead to some confusion -- which is why I try to use "pointer" as an adjective rather than as a noun.
The C standard, at least in some cases, uses the word "pointer" to mean "pointer value". For example, the description of malloc says it "returns either a null pointer or a pointer to the allocated space".
So what's an address in C? It's a pointer value, i.e., a value of some particular pointer type. (Except that a null pointer value is not necessarily referred to as an "address", since it isn't the address of anything).
The standard's description of the unary
&
operator says it "yields the address of its operand". Outside the C standard, the word "address" is commonly used to refer to a (physical or virtual) memory address, typically one word in size (whatever a "word" is on a given system).A C "address" is typically implemented as a machine address -- just as a C
int
value is typically implemented as a machine word. But a C address (pointer value) is more than just a machine address. It's a value typically represented as a machine address, and it's a value with some specific type.A pointer value is an address. A pointer variable is an object that can store an address. This is true because that's what the standard defines a pointer to be. It's important to tell it to C novices because C novices are often unclear on the difference between a pointer and the thing it points to (that is to say, they don't know the difference between an envelope and a building). The notion of an address (every object has an address and that's what a pointer stores) is important because it sorts that out.
However, the standard talks at a particular level of abstraction. Those people the author talks about who "know what addresses are about", but who are new to C, must necessarily have learned about addresses at a different level of abstraction -- perhaps by programming assembly language. There is no guarantee that the C implementation uses the same representation for addresses as the CPUs opcodes use (referred to as "the store address" in this passage), that these people already know about.
He goes on to talk about "perfectly reasonable address manipulation". As far as the C standard is concerned there's basically no such thing as "perfectly reasonable address manipulation". Addition is defined on pointers and that is basically it. Sure, you can convert a pointer to integer, do some bitwise or arithmetic ops, and then convert it back. This is not guaranteed to work by the standard, so before writing that code you'd better know how your particular C implementation represents pointers and performs that conversion. It probably uses the address representation you expect, but it it doesn't that's your fault because you didn't read the manual. That's not confusion, it's incorrect programming procedure ;-)
In short, C uses a more abstract concept of an address than the author does.
The author's concept of an address of course is also not the lowest-level word on the matter. What with virtual memory maps and physical RAM addressing across multiple chips, the number that you tell the CPU is "the store address" you want to access has basically nothing to do with where the data you want is actually located in hardware. It's all layers of indirection and representation, but the author has chosen one to privilege. If you're going to do that when talking about C, choose the C level to privilege!
Personally I don't think the author's remarks are all that helpful, except in the context of introducing C to assembly programmers. It's certainly not helpful to those coming from higher level languages to say that pointer values aren't addresses. It would be far better to acknowledge the complexity than it is to say that the CPU has the monopoly on saying what an address is and thus that C pointer values "are not" addresses. They are addresses, but they may be written in a different language from the addresses he means. Distinguishing the two things in the context of C as "address" and "store address" would be adequate, I think.
Simply to say pointers are actually offset part of the segmentation mechanism which translate to Linear Address after segmentation and then to Physical address after paging. Physical Addresses are actually addressed from you ram.