41

When you learn C++, or at least when I learned it through C++ Primer, pointers were termed the "memory addresses" of the elements they point to. I'm wondering to what extent this is true.

For example, do two elements *p1 and *p2 have the property p2 = p1 + 1 or p1 = p2 + 1 if and only if they are adjacent in physical memory?

fuz
  • 88,405
  • 25
  • 200
  • 352
user5648283
  • 5,913
  • 4
  • 22
  • 32
  • 13
    The *memory* we talk about in program is essentially virtual memory, whose address will be translated by the MMU of the operating system, to the actual physical memory address. – Haris Dec 29 '15 at 14:09
  • 8
    Neither C nor C++ have a concept of "physicality". They only have *memory*, which is some abstract, addressable entity. How this memory is realized in practice depends on the platform and execution environment. – Kerrek SB Dec 29 '15 at 14:17
  • 1
    I'd say that it's a little bit more precise to say that a pointer variable *contains* a memory address - and that address may or may not be valid. – Andrew Henle Dec 29 '15 at 14:23
  • 8
    There is no language called C/C++. Please choose at most one of C and C++ for this question. – fuz Dec 29 '15 at 14:25
  • 2
    How the conditions given for pointers `p1` and `p2` are contradicting the fact pointers are actually memory addresses? – Amit Upadhyay Dec 29 '15 at 14:27
  • @FUZxxl: While I agree in general, I'm not aware of any meaning full distinctions between the pointer concepts in c and c++ (I believe, there are some subtle differences concerning legal pointer operations, but - to my knowledge - they are not relevant for the question or the answers). So I don't see any reason not to ask about the pointer concept in C and C++ in the same question. – MikeMB Dec 29 '15 at 14:32
  • 2
    @MikeMB C and C++ have [many subtle differences](http://stackoverflow.com/a/31505447/417501), especially when it comes to what you can assume about primitive things like pointers. Considering C and C++ as “almost the same” is wrong and a sign of total ignorance of the differences (which bite you where you least expect them). – fuz Dec 29 '15 at 14:36
  • @MikeMB Reading your comment again and putting it in context of your question: You ask about subtle details of how pointers work in C and C++ and then you say that you think the subtle differences of how pointers work between C and C++ are not relevant for this question? – fuz Dec 29 '15 at 14:38
  • @FUZxxl: What question? – MikeMB Dec 29 '15 at 14:40
  • @MikeMB The questions you ask in the question we are discussing right now (the question this comment thread is attached to). – fuz Dec 29 '15 at 14:42
  • 1
    @FUZxxl: I didn't ask that question - user5648283 did. – MikeMB Dec 29 '15 at 14:43
  • 2
    @MikeMB Oh yeah, why didn't I realize. Still, my point stands: The subtle differences between C and C++ make it impossible to answer this question for both in a meaningful way and answering questions for multiple languages at once is something we usually don't do on Stack Overflow. – fuz Dec 29 '15 at 14:45
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/99213/discussion-between-mikemb-and-fuzxxl). – MikeMB Dec 29 '15 at 14:46
  • 1
    C++ is a superset of C, and the topic I've presented is a subset of C. Therefore this question pertains to both C and C++. – user5648283 Dec 29 '15 at 14:56
  • 13
    @user5648283: C++ is not a strict superset of C. – MikeMB Dec 29 '15 at 15:02
  • 2
    For this question, the architecture, on which the Program runs (e.g. not all devices have a MMU, many devices don't have continuous physical address space) might actually be more important than the distinction between C and C++. I am all about treating C and C++ as separate languages by default, but saying that the question can't be answered for C and C++ at the same time seems to be a little over-zealous. E.g. as most answers have demonstrated, one can first talk about the things that are true for both languages and then add the c++ specific part if necessary. – MikeMB Dec 29 '15 at 15:50
  • 1
    You know, there were architectures in common use not too long ago where some of these assumptions weren't actually true of memory addresses. – Random832 Dec 29 '15 at 16:08
  • 2
    The possibility of segmented architectures certainly [complicates any assumptions you can make](http://stackoverflow.com/a/31151779/1708801). – Shafik Yaghmour Dec 29 '15 at 16:27
  • c++ can be used to create firmwares for various devices, which would allow to run it on bare hardware without operating system in between. So the whole virtual address space discussion is pretty much irrelevant unless you are able to cite standard on that matter – n0rd Dec 29 '15 at 20:45
  • @n0rd, ...so, because it's *possible* for C++ to be used to write programs that run in real mode, the fact that a set of assumptions can be broken when *not* targeting real mode is irrelevant? How does that work? – Charles Duffy Dec 29 '15 at 20:50
  • C++ is fit for both protected and real modes, so either standard has some definitions regarding these modes, or they are irrelevant to C++ *language* (but may be relevant to specific compiler implementation/target environment). Since no details about compile- and run-time environments are defined, I presume we are discussing language here, and then it would be nice to support virtual addressing claims with standard references or dismiss them as irrelevant. – n0rd Dec 29 '15 at 21:12
  • @n0rd: If you look at the question from a language-laywer perspective you can Ignore all the virtual/physical addressing stuff and I'd recommend the excellent answer from lightness Races in orbit. However, as user5648283 was explicitly talking about hw-memory-addresses, I think it is ok to talk about that relationship in the context of actual implementations, but I agree, that the questions lacks infos about which implementation that should be (in which case I usually assume, we are talking about a modern compiler for windows and/or linux on arm or x86) – MikeMB Dec 29 '15 at 22:11
  • 1
    Possible duplicate of [What exactly is a C pointer if not a memory address?](http://stackoverflow.com/questions/15151377/what-exactly-is-a-c-pointer-if-not-a-memory-address) – Rolf ツ Dec 29 '15 at 23:13
  • Excellent answer here: http://stackoverflow.com/a/15166023/1052697 – Rolf ツ Dec 29 '15 at 23:13
  • @Rolfツ that is a C thread; this is a C++ question. The two languages have slightly different memory models and the respective standards documents use different wording. – M.M Jan 25 '16 at 21:48

12 Answers12

32

You should think of pointers as being addresses of virtual memory: modern consumer operating systems and runtime environments place at least one layer of abstraction between physical memory and what you see as a pointer value.

As for your final statement, you cannot make that assumption, even in a virtual memory address space. Pointer arithmetic is only valid within blocks of contiguous memory such as arrays. And whilst it is permissible (in both C and C++) to assign a pointer to one point past an array (or scalar), the behaviour on deferencing such a pointer is undefined. Hypothesising about adjacency in physical memory in the context of C and C++ is pointless.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 2
    Shouldn't pointer arithmetic be correct more generally on contiguous memory and not only on arrays? – terence hill Dec 29 '15 at 14:24
  • 1
    chance allocation of linked list nodes beside each other(just kidding).. BTW this is a better answer then the highest voted one. +1 – Haris Dec 29 '15 at 14:28
  • @terencehill: yes I was thinking about this. I don't think it's worth complicating this answer by restricting arithmetic to just arrays. I've reworded. Thank you. – Bathsheba Dec 29 '15 at 14:29
  • p1 could be at the end of an mmu block and p2 the beginning of another, so that in virtual space they are adjacent (arrays are not relevant here), but in physical space they can be nowhere near each other. so the posters statement about being adjacent in physical space is just adding to their confusion. – old_timer Dec 29 '15 at 14:52
  • 1
    modern *consumer* operating systems place at least one layer of abstraction. Almost all embedded os's have an option to use a flat memory space. – Sam Dec 29 '15 at 20:10
17

Not at all.

C++ is an abstraction over the code that your computer will perform. We see this abstraction leak in a few places (class member references requiring storage, for example) but in general you will be better off if you code to the abstraction and nothing else.

Pointers are pointers. They point to things. Will they be implemented as memory addresses in reality? Maybe. They could also be optimised out, or (in the case of e.g. pointers-to-members) they could be somewhat more complex than a simple numeric address.

When you start thinking of pointers as integers that map to addresses in memory, you begin to forget for example that it's undefined to hold a pointer to an object that doesn't exist (you can't just increment and decrement a pointer willy nilly to any memory address you like).

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • "you can't just increment and decrement a pointer willy nilly to any memory address you like" - well, you *can*, it's just not a very good idea. – fluffy Dec 29 '15 at 23:41
  • 4
    @fluffy: No it's more than "not a very good idea". It has undefined behaviour. So you "can" in the same way that you "can" read destroyed data through dangling pointers, "can" modify a `const` object using `const_cast`, and "can" murder a room full of people with a stanley knife. The standard does not allow a well-formed program to do any of those things. It's not just a style thing. – Lightness Races in Orbit Dec 29 '15 at 23:46
  • Well, yeah, that was my point. It's possible - you *can*. It's just undefined behavior pretty much most of the time, although not always (such as memory-mapped I/O on embedded systems and the like, like Arduino or old-school real-mode DOS and the like). – fluffy Dec 29 '15 at 23:49
  • @fluffy: This question is about what is acceptable in C++, not about what is physically possible on a computer. You can write programs that hack about with memory and take advantage of platform-specific trickery, but that no longer counts as writing C++. – Lightness Races in Orbit Dec 29 '15 at 23:49
11

As many answers have already mentioned, they should not be thought of as memory addresses. Check out those answers and here to get an understanding of them. Addressing your last statement

*p1 and *p2 have the property p2 = p1 + 1 or p1 = p2 + 1 if and only if they are adjacent in physical memory

is only correct if p1 and p2 are of the same type, or pointing to types of the same size.

Community
  • 1
  • 1
Aiden Deom
  • 916
  • 5
  • 11
  • 3
    Not exactly. `p1` and `p2` must point to adjacent elements of the same array. Btw, this is not a property of `*p1` and `*p2` – chqrlie Dec 29 '15 at 14:26
  • `p1` and `p2` do not need to be pointing to objects in an array. All they need to be pointing to is objects that are next to each other in memory. that just happens to be the case when they are in an array (and those objects will also be of the same type). I agree with you that it is not a property of `*p1` and `*p2`. I was just quoting the original question. I should have been more clear – Aiden Deom Dec 29 '15 at 14:44
  • 3
    If `p1` and `p2` point to different objects of the same type that are not part of the same array, there is no guarantee that `p1 == p2 + 1` even if `(uintptr_t)p1 == (uintptr_t)(p2 + 1)`. – chqrlie Dec 29 '15 at 14:51
  • I agree with you. However, the original statement said that it holds **iff** they are adjacent in memory. Being neighboring elements in an array satisfies this condition, as you've pointed out, but it is not the only case in which this constraint is satisfied – Aiden Deom Dec 29 '15 at 14:55
  • 1
    Now I change my mind. A pointer is not an address, in general. It may hold no-address ID. – haccks Dec 29 '15 at 15:05
  • 3
    _"It is indeed acceptable to think of pointers as memory addresses"_ No it's irresponsible. – Lightness Races in Orbit Dec 29 '15 at 15:23
  • @LightnessRacesinOrbit I read your answer and I'm not sure I understand why it is irresponsible to think in such a way. As far as the question goes, OP never asks about dereferencing the pointer; just that if two pointers (pointing to objects of the same type/size) hold the property `p2 == p1 + 1` then they are adjacent – Aiden Deom Dec 29 '15 at 15:32
  • @AidenDeom; You missed OP's first question. – haccks Dec 29 '15 at 15:33
  • @AidenDeom: That's not the same as asking whether it's acceptable to think of pointers as memory addresses. – Lightness Races in Orbit Dec 29 '15 at 15:34
  • @LightnessRacesinOrbit My mistake. I learned something new. I've adjusted my answer, I hope it is not blatantly incorrect now – Aiden Deom Dec 29 '15 at 15:58
  • 1
    Lol well you're entitled to your opinion. I was just explaining my downvote because I hold a different opinion. Seems a bit weird to summarily invert your answer with all those votes on it? Oh well – Lightness Races in Orbit Dec 29 '15 at 15:59
  • @LightnessRacesinOrbit But I mean is it an opinion? From what I've read in these answers and others, I was wrong. I don't really want to be spreading false information lol – Aiden Deom Dec 29 '15 at 16:05
  • @AidenDeom: Well this topic does seem subjective. I stand by my viewpoint vehemently but I'm not ignorant to the fact that many disagree for whatever reason. I think that's enough to call it an opinion - I'm not a bigot :P – Lightness Races in Orbit Dec 29 '15 at 16:07
5

Absolutely right to think of pointers as memory addresses. That's what they are in ALL compilers that I have worked with - for a number of different processor architectures, manufactured by a number of different compiler producers.

However, the compiler does some interesting magic, to help you along with the fact that normal memory addresses [in all modern mainstream processors at least] are byte-addresses, and the object your pointer refers to may not be exactly one byte. So if we have T* ptr;, ptr++ will do ((char*)ptr) + sizeof(T); or ptr + n is ((char*)ptr) + n*sizeof(T). This also means that your p1 == p2 + 1 requires p1 and p2 to be of the same type T, since the +1 is actually +sizeof(T)*1.

There is ONE exception to the above "pointers are memory addresses", and that is member function pointers. They are "special", and for now, please just ignore how they are actually implemented, sufficient to say that they are not "just memory addresses".

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • 3
    _"That's what they are in ALL compilers that I have worked with"_ You're throwing away the abstraction because all known implementations are the same. Might as well say "references are pointers". – Lightness Races in Orbit Dec 29 '15 at 15:23
  • 1
    @LightnessRacesinOrbit: you seem to forget that many programmers need to think in terms of concrete things. It is difficult enough for most to understand the concept of pointers to throw away simple implementation examples that are easy to manipulate and play with. For most purposes, C++ references are implemented as pointers with implicit dereferencing. The nice feature about references besides the simpler syntax and convenience for operator overloading is the guarantee that they are not null. – chqrlie Dec 29 '15 at 17:38
  • 3
    @chqrlie: _"you seem to forget that many programmers need to think in terms of concrete things"_ IMO programmers must learn to think in abstractions in order to be effective at writing robust, reliable and reusable code. Thinking in terms of implementation details all the time is a starting point at best, certainly not a desirable end goal. – Lightness Races in Orbit Dec 29 '15 at 17:40
  • 1
    @LightnessRacesinOrbit: I did not say that, I merely indicated that many beginners need concrete examples to grasp some concepts... C is not the best language to learn to program with abstractions. Lisp, OCaml, Prolog, F# are more appropriate for that. Programmers that understand implementation details have strong advantage to learn C concepts, simple ones but still out of reach for so many beginners. – chqrlie Dec 29 '15 at 17:48
  • Can I just ask what that abstraction buys us? The possibility to build a compiler that doesn't do that, yes. But in practice, it's still true that compilers do indeed implement pointers as addresses. Not only in C and C++, but also in Pascal, Modula-{2,3} and any other language that I'm aware of that has a concept of pointers. And yes, to me, as a person that tries to understand what the compiler actually does, rather than see it as an opaque shield to defend me against the evils of hardware - as mentioned above, there are plenty of other languages that shield much better. – Mats Petersson Dec 29 '15 at 21:20
5

The operating system provides an abstraction of the physical machine to your program (i.e. your program runs in a virtual machine). Thus, your program does not have access to any physical resource of your computer, be it CPU time, memory, etc; it merely has to ask the OS for these resources.

In the case of memory, your program works in a virtual address space, defined by the operating system. This address space has multiple regions, such as stack, heap, code, etc. The value of your pointers represent addresses in this virtual address space. Indeed, 2 pointers to consecutive addresses will point to consecutive locations in this address space.

However, this address space is splitted by the operating system into pages and segments, which are swapped in and out from memory as required, so your pointers may or may not point to consecutive physical memory locations and is impossible to tell at runtime if that is true or not. This also depends on the policy used by the operating system for paging and segmentation.

Bottom line is that pointers are memory addresses. However, they are addresses in a virtual memory space and it is up to the operating system to decide how this is mapped to the physical memory space.

As far as your program is concerned, this is not an issue. One reason for this abstraction is to make programs believe they are the only users of the machine. Imagine the nightmare you'd have to go through if you would need to consider the memory allocated by other processes when you write your program - you don't even know which processes are going to run concurrently with yours. Also, this is a good technique to enforce security: your process cannot (well, at least shouldn't be able to) access maliciously the memory space of another process since they run in 2 different (virtual) memory spaces.

Paul92
  • 8,827
  • 1
  • 23
  • 37
4

Like other variables, pointer stores a data which can be an address of memory where other data is stored.

So, pointer is a variable that have an address and may hold an address.

Note that, it is not necessary that a pointer always holds an address. It may hold a non-address ID/handle etc. Therefore, saying pointer as an address is not a wise thing.


Regarding your second question:

Pointer arithmetic is valid for contiguous chunk of memory. If p2 = p1 + 1 and both pointers are of same type then p1 and p2 points to a contiguous chunk of memory. So, the addresses p1 and p2 holds are adjacent to each other.

Community
  • 1
  • 1
haccks
  • 104,019
  • 25
  • 176
  • 264
  • "You can say that pointers are actually memory addresses." I know I can say that, but is it true? – user5648283 Dec 29 '15 at 14:13
  • 2
    @user5648283: no it is not true, pointers are variables whose values are addresses. – chqrlie Dec 29 '15 at 14:29
  • @chqrlie; Every variable has two aspects, when used as lvalue then it act as an address and when used as an rvalue then act as the value at memory address. For pointers, in both cases its a memory address. – haccks Dec 29 '15 at 14:31
  • yes, but your wording is as ambiguous as the OPs: If `p2 == p1 + 1`, then `p1` and `p2` **point** to adjacent objects in memory. The pointers `p1` and `p2` themselves may be anywhere in memory, or not even in memory at all. – chqrlie Dec 29 '15 at 14:37
  • 1
    _"A variable is named memory location where data is stored"_ Gross oversimplification. Ignores the entire abstraction and its purpose. – Lightness Races in Orbit Dec 29 '15 at 15:22
  • @LightnessRacesinOrbit; No need to expand it much in this case. – haccks Dec 29 '15 at 15:32
  • @haccks: I disagree as this is the whole salient point of the question. – Lightness Races in Orbit Dec 29 '15 at 15:34
  • @LightnessRacesinOrbit; To me salient point of the question is *whether a pointer is an address or not*? – haccks Dec 29 '15 at 15:35
  • 1
    @haccks: Right. And the answer is _no_ :) You instead answered "yes" using the rationale _"A variable is named memory location where data is stored"_ which is broken because it's a gross oversimplification that ignores the entire abstraction and its purpose – Lightness Races in Orbit Dec 29 '15 at 15:59
4

I think this answer has the right idea but poor terminology. What C pointers provide are the exact opposite of abstraction.

An abstraction provides a mental model that's relatively easy to understand and reason about, even if the hardware is more complex and difficult to understand or harder to reason about.

C pointers are the opposite of that. They take possible difficulties of the hardware into account even when though the real hardware is often simpler and easier to reason about. They limit your reasoning to what's allowed by a union of the most complex parts of the most complex hardware regardless of how simple the hardware at hand may actually be.

C++ pointers add one thing that C doesn't include. It allows comparing all pointers of the same type for order, even if they're not in the same array. This allows a little more of a mental model, even if it doesn't match the hardware perfectly.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • "the exact opposite of abstraction" is an interesting idea, but I can't wrap my mind around it. When you say "limiting one's reasoning" you're describing just one of key features of *abstractions*. It doesn't matter whether pointers are simpler than *some* possible hardware paradigms. What does matter is that what hardware does is *always* irrelevant - and that's abstraction. I agree that it may be perceived as counter-intuitive when the abstract model is not simpler than one architecture, but it's not the complexity that's being abstracted away - it's the *details* of all architectures. – BartoszKP Dec 29 '15 at 23:09
  • @BartoszKP: Sorry, but I have to disagree. To qualify as an abstraction, it must provide a model that's more, well...abstract. In this case, the model is provides is *less* abstract than almost any current hardware provides. Just being *different* from the hardware doesn't make it an abstraction. – Jerry Coffin Dec 30 '15 at 05:36
  • Ignotum per ignotum ;p I didn't say that it's enough to be *different* - what I mean is, it's enough *making some details irrelevant* to qualify for an abstraction. – BartoszKP Dec 30 '15 at 09:19
  • @BartoszKP: That's exactly what *doesn't* happen here though.Rather than making some details irrelevant, it forces one to take into account the union of all the details of all the architectures of which anybody was aware (i.e., essentially everything), regardless of the fact that most of them can't apply in any one case, and virtually none of them apply in most. – Jerry Coffin Dec 30 '15 at 12:33
  • These are different details, which look the same as the ones you speak of :) This may seem like a subtle game of words, but I think it's meaningful here: the details of the abstract model, perhaps make it more complex, but they allow you to ignore the fact whether corresponding details exist in the underlying architecture and in what configuration. You are not dependent on them whatsoever. – BartoszKP Dec 30 '15 at 13:13
  • A *good* abstraction will provide a model that's easier to reason about than the one being abstracted. What C provides is the opposite of a *good* abstraction, but I think it's still an abstraction. – supercat Sep 17 '18 at 21:04
1

Somehow answers here fail to mention one specific family of pointers - that is, pointers-to-members. Those are certainly not memory addresses.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • Pointers to members. Member pointers are not special by the virtue of being members. – SergeyA Dec 29 '15 at 14:33
  • I think this refers to pointer to member functions (which I did cover in my answer) – Mats Petersson Dec 29 '15 at 14:39
  • @MatsPetersson, pointers to non-function members are special as well. – SergeyA Dec 29 '15 at 14:42
  • Technically, the C++ Standard refers to *pointer-to-member* operators and *pointer to member of T* for the specific thing you are referring to, which by the way can be members or not. This is a tad confusing, since one can also have pointer members, and pointers that point to members of a specific instance, both of which are actual pointers (they hold addresses). – chqrlie Dec 29 '15 at 14:46
1

Unless pointers are optimized out by the compiler, they are integers that store memory addresses. Their lenght depends on the machine the code is being compiled for, but they can usually be treated as ints.

In fact, you can check that out by printing the actual number stored on them with printf().

Beware, however, that type * pointer increment/decrement operations are done by the sizeof(type). See for yourself with this code (tested online on Repl.it):

#include <stdio.h>

int main() {
    volatile int i1 = 1337;
    volatile int i2 = 31337;
    volatile double d1 = 1.337;
    volatile double d2 = 31.337;
    volatile int* pi = &i1;
    volatile double* pd = &d1;
    printf("ints: %d, %d\ndoubles: %f, %f\n", i1, i2, d1, d2);
    printf("0x%X = %d\n", pi, *pi);
    printf("0x%X = %d\n", pi-1, *(pi-1));
    printf("Difference: %d\n",(long)(pi)-(long)(pi-1));
    printf("0x%X = %f\n", pd, *pd);
    printf("0x%X = %f\n", pd-1, *(pd-1));
    printf("Difference: %d\n",(long)(pd)-(long)(pd-1));
}

All variables and pointers were declared volatile so as the compiler wouldn't optimize them out. Also notice that I used decrement, because the variables are placed in the function stack.

The output was:

ints: 1337, 31337
doubles: 1.337000, 31.337000
0xFAFF465C = 1337
0xFAFF4658 = 31337
Difference: 4
0xFAFF4650 = 1.337000
0xFAFF4648 = 31.337000
Difference: 8

Note that this code may not work on all compilers, specially if they do not store variables in the same order. However, what's important is that the pointer values can actually be read and printed and that decrements of one may/will decrement based on the size of the variable the pointer references.

Also note that the & and * are actual operators for reference ("get the memory address of this variable") and dereference ("get the contents of this memory address").

This may also be used for cool tricks like getting the IEEE 754 binary values for floats, by casting the float* as an int*:

#include <iostream>

int main() {
    float f = -9.5;
    int* p = (int*)&f;

    std::cout << "Binary contents:\n";
    int i = sizeof(f)*8;
    while(i) {
        i--;
        std::cout << ((*p & (1 << i))?1:0);
   } 
}

Result is:

Binary contents:
11000001000110000000000000000000 

Example taken from https://pt.wikipedia.org/wiki/IEEE_754. Check out on any converter.

Ronan Paixão
  • 8,297
  • 1
  • 31
  • 27
0

Pointers are memory addresses, but you shouldn't assume they reflect physical address. When you see addresses like 0x00ffb500 those are logical addresses that the MMU will translate to the corresponding physical address. This is the most probable scenario, since virtual memory is the most extended memory management system, but there could be systems that manage physical address directly

Mr. E
  • 2,070
  • 11
  • 23
0

The particular example you give:

For example, do two elements *p1 and *p2 have the property p2 = p1 + 1 or p1 = p2 + 1 if and only if they are adjacent in physical memory?

would fail on platforms that do not have a flat address space, such as the PIC. To access physical memory on the PIC, you need both an address and a bank number, but the latter may be derived from extrinsic information such as the particular source file. So, doing arithmetic on pointers from different banks would give unexpected results.

Owen
  • 38,836
  • 14
  • 95
  • 125
0

According to the C++14 Standard, [expr.unary.op]/3:

The result of the unary & operator is a pointer to its operand. The operand shall be an lvalue or a qualified-id. If the operand is a qualified-id naming a non-static member m of some class C with type T, the result has type “pointer to member of class C of type T” and is a prvalue designating C::m. Otherwise, if the type of the expression is T, the result has type “pointer to T” and is a prvalue that is the address of the designated object or a pointer to the designated function. [Note: In particular, the address of an object of type “cv T” is “pointer to cv T, with the same cv-qualification. —end note ]

So this says clearly and unambiguously that pointers to object type (i.e. a T *, where T is not a function type) hold addresses.


"address" is defined by [intro.memory]/1:

The memory available to a C++ program consists of one or more sequences of contiguous bytes. Every byte has a unique address.

So an address may be anything which serves to uniquely identify a particular byte of memory.

Note: In the C++ standard terminology, memory only refers to space that is in use. It doesn't mean physical memory, or virtual memory, or anything like that. The memory is a disjoint set of allocations.


It is important to bear in mind that, although one possible way of uniquely identifying each byte in memory is to assign a unique integer to each byte of physical or virtual memory, that is not the only possible way.

To avoid writing non-portable code it is good to avoid assuming that an address is identical to an integer. The rules of arithmetic for pointers are different to the rules of arithmetic for integers anyway. Similarly, we would not say that 5.0f is the same as 1084227584 even though they have identical bit representations in memory (under IEEE754).

M.M
  • 138,810
  • 21
  • 208
  • 365