1

this is my first question in this forum, sorry my bad english. I have a question about pointers and dynamic memory in c++.

Example, this code:

#include <iostream>

using namespace std;

int main(int argc, char const *argv[])
{
  int *a = new int;

  for (int i = 0; i < 5; i++)
    cout << a++ << endl;

  return 0;
}

Output:

0x11d4c20
0x11d4c24
0x11d4c28
0x11d4c2c
0x11d4c30

My question, is why can I move more than that 'single' block of memory that I created with new.

  • What is a pointing to?

Same occurs with new int[], even if I specific the size:

#include <iostream>

using namespace std;

int main(int argc, char const *argv[])
{
  int *a = new int[2];

  for (int i = 0; i < 5; i++)
    cout << a++ << endl;

  return 0;
}

Output:

0x2518c20
0x2518c24
0x2518c28
0x2518c2c
0x2518c30

Again, what is happening?

  • What is a pointing to?

Does all of this mean I'm violating memory?

  • 1
    It's a pointer, so you can perform pointer arithmetic. There is nothing performing any checks for you whether it's actually still pointing to valid data that is on the programmer (i.e.: you). And if you move past the allocated memory with your pointer you are invoking undefined behaviour (you are accessing "random" data) – UnholySheep Oct 29 '16 at 18:03
  • Take a look at [this question](http://stackoverflow.com/questions/4998939/how-does-unary-addition-on-c-pointers-work) – code_dredd Oct 29 '16 at 18:04
  • @UnholySheep I understand the pointers behavior, so `a` is just pointing to "random" data? – Kevin Del Castillo Ramirez Oct 29 '16 at 18:07
  • You're neither accessing nor _not_ accessing anything; the behaviour undefined. It's like asking what colour my voice is; it's nonsense and cannot be rationalised about (in the context of the language) – Lightness Races in Orbit Oct 29 '16 at 18:17
  • `Does all of this mean I'm violating memory?` If you try and read or write to the memory location beyond allocated memory that will invoke undefined behavior (potential crash). – Martin York Oct 31 '16 at 13:42

4 Answers4

1

a is an int*, not an int. What you are printing is actually the pointer, i.e. the memory address of the pointed object. Use the dereference operator * whenever you want to modify the pointed value, i.e.

cout << (*a)++ << endl;

NB: Likewise, you can get a pointer to an int using the reference operator, &, not to be mixed up with a reference (e.g. a int& type).

This may print 0 1 2 3 4. may because you are not initializing the new int created in dynamic memory. This means reading from *a (dereferenced a) is undefined behavior, which means your program may misbehave. You have to change your line using new:

int *a = new int();

This will initialize *a to 0 and now 0 1 2 3 4 will be printed correctly.

Note that int *a = new int[2]; does create a dynamic array of 2 entries in dynamic memory, which means *(a + 1) can be used as well (as if it was a regular array). It does not initialize *a to 2.

Do remember to delete a; when you've done using it. In a real application, you could get a memory leak if you don't - i.e. your program would still use memory it doesn't need anymore. Caution, when you have to delete a dynamically-allocated array (i.e. new int[2]), you need to use delete[] a; instead, or you will trigger undefined behavior.

You may also use a unique_ptr (or a shared_ptr) in C++11 as an alternative to this kind of memory allocation, i.e. :

#include <memory>
// ...
std::unique_ptr<int> a = std::make_unique<int>(0);

Thanks to this solution, you do not need to delete a because the unique_ptr will do this for you, when itself dies (i.e. out of the scope, here).

Edit: Bonus:

0x2518c20
0x2518c24
0x2518c28

Why is the number incremented by 4 if you just used ++?

Using ++ on an address will actually increment it by sizeof(T), which here is sizeof(int) and not 1. This explains why you can, as previously stated, use *(a + 1) if you used new int[2].

asu
  • 1,875
  • 17
  • 27
  • Sorry, if I not explained myself, I know how to work with pointers (difference between `a` and `*a`) , my question is what is `a` pointing to? and if can I read and modify data from that block. – Kevin Del Castillo Ramirez Oct 29 '16 at 18:18
  • `a` is pointing to memory allocated (very likely) in the heap. Reading `*a` is legal. Reading `*(a + 1)` isn't, since you didn't allocate that memory with the `new`. – asu Oct 29 '16 at 18:20
  • @Lightness Races in Orbit why is it UB even if you don't read `*a` after increment `a`? – asu Oct 29 '16 at 18:22
  • 2
    @Asu: Because the standard says so. C++ is an abstraction, and pointers are more than just numbers; they point to _things_. It makes no sense to have a pointer that points to _random empty space_ (null pointers and one-past-the-end pointers being deliberate exceptions for good reason) – Lightness Races in Orbit Oct 29 '16 at 18:23
0

i think that it is ,because a points to an integer , the size of an integer is 4 bytes (sizeof(int) == 4) after executing a++ ,a points to the next integer,try char *a, and a++ to be more sure

Toufik ID
  • 50
  • 6
0

It is legal to point at an object or the spot right after an object. A new int[2] creates two adjacent objects (in an array) and returns a pointer to the first one.

So yes, what you did above is not permitted. The behaviour of adding 5 to a pointer to a single object is not defined by the C++ standard; the compiler can generate assembly that does anything at all.

As it happens, on a flat memory architecture, pointers are basically unsigned integers. And incrementing a pointer by 1 is just incrementing it by the size of the pointed-to object.

So what often happens is you just get pointers to whatever happens to be there.

Now this is not guaranteed and should not be relied upon. Many of the rules of C++ that make actions undefined permit certain optimizations to occur over the "naive" mapping you might think the compiler does. For example, pointers to short can never point to an int and change its value in a defined way, which means if a function has both an int and short pointer it can assume that a write to the short does not modify the int.

The naive "write to the two words in an int" method of using shorts can work, then not work for seeming no reason, because the behaviour was undefined and the compiler was free to optimize assuming it could not happen.

In short, your actions are not legal, the behaviour you got is not surprising, but you can never rely on it.

Pointers are not just unsigned integers, even if that is what your compiler implements them with. They are an abstraction. Their behaviour is determined not by their implementation, but rather what the standard permits you do with them. When you act in ways the standard does not permit, the behaviour you get is undefined by the standard. Compilers can, and have been known to, exploit that fact to assume undefined behaviour cannot and does not occur. The program could behave unexpectedly on lines of code prior to the undefined behaviour as the compiler reorders and optimizes based on the assumption your code has well defined behaviour.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
-1

Pointers in c++ (and c) are just addresses to the memory (32/64bit numbers). There is no problem with increasing them or decreasing any way you want and you are not violating the memory or any other rule. You would be however violating the memory if you tried to read or write to the address pointed to by A after going through the for cycle.

As for what it is pointing to, most likely it's just some more space allocated to you by the new (and malloc under it) because it tends to give more space than you ask for, though this behaviour is not guaranteed. It might also point to heap data or just unassigned memory.

Rasty
  • 301
  • 1
  • 10
  • *"most likely it's just some more space allocated to you by the `new`"* - what makes you think that? – UnholySheep Oct 29 '16 at 18:14
  • _"Pointers in c++ (and c) are just adresses to the memory (32/64bit numbers)."_ No, not really. – Lightness Races in Orbit Oct 29 '16 at 18:14
  • _"There is no problem with increasing them or decreasing any way you want and you are not violating the memory or any other rule"_ This is wrong. The increment has UB. – Lightness Races in Orbit Oct 29 '16 at 18:14
  • @UnholySheep personal experience and logical thinking. It mostly gives blocks of 16 bytes if I am not mistaken, but it depends on implementation. – Rasty Oct 29 '16 at 18:16
  • @LightnessRacesinOrbit from data perspective this is the truth, though arithmetic operations act a bit different, the data itself is just a simple number. Exactly the one that gets printed out. And I don't know what you mean by UB. – Rasty Oct 29 '16 at 18:19
  • 2
    Your personal experience seems to be rather limited in that case. There is absolutely no guarantee or requirement for a compiler to allocate more memory than requested in a call to `new`. In fact, it's even different in the same compiler depending on which architecture it compiles for (see [GCC documentation](http://www.gnu.org/software/libc/manual/html_node/Aligned-Memory-Blocks.html)) – UnholySheep Oct 29 '16 at 18:19
  • @UnholySheep I specifically said this behavior is not guaranteed. It is just more likely that you will encounter exactly this case than not encountering it. – Rasty Oct 29 '16 at 18:21
  • Even if it does happen, you are still making use of UB. Your compiler can optimise away your code as being nonsensical within the context of the computer program you're creating. – Lightness Races in Orbit Oct 29 '16 at 18:24
  • @LightnessRacesinOrbit no. As long as you are not trying to access the memory data, there is no UB. Pointers don't care whether their values are allocated or not. You might even want to use not valid pointers (like NULL). And my answer was to what the pointer is pointing at, not whether you should use this space for anything. – Rasty Oct 29 '16 at 18:28
  • @Rasty: _"from data perspective this is the truth, though arithmetic operations act a bit different, the data itself is just a simple number."_ You are mistaken. The standard clearly states that using pointer arithmetic in this manner has undefined behaviour. – Lightness Races in Orbit Oct 29 '16 at 18:28
  • 1
    @Rasty: _"As long as you are not trying to access the memory data, there is no UB."_ Again, you are mistaken. NULL and the one-past-the-end pointer are exceptions. I suggest that you read the relevant standard sections, to refresh your knowledge. – Lightness Races in Orbit Oct 29 '16 at 18:28
  • Pls. link. I can't imagine in what way just adding arbitrary number to a pointer can cause UB. – Rasty Oct 29 '16 at 18:30
  • That *"article"* is the documentation for one specific compiler. It is no guarantee whatsoever that any other compiler does the exact same thing. And since you pointed out *"the first sentence"* - it proves that you were wrong (claiming compilers allocate blocks of 16 bytes). In fact one much used counter-example is VC++ 2012 (see their [documentation](https://msdn.microsoft.com/en-us/library/ycsb6wwf(v=vs.110).aspx)) – UnholySheep Oct 29 '16 at 18:30
  • 1
    It's `[expr.add]/5` in C++14. You cannot "cause" UB. Undefined behaviour is what your program has when you do something in your program that makes no sense, according to the rules of the abstract programming language called C++. And having a pointer that points to random empty space makes no sense. C++ is not assembly; if you want direct memory access, use that! It seems you seriously underestimate the amount of optimisation that a modern C++ compiler performs to produce a useful executable; to do so, it needs strong guarantees, and the standard provides those ... for a program without UB. – Lightness Races in Orbit Oct 29 '16 at 18:30
  • Thanks, so for the specification: "If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, **the evaluation** shall not produce an overflow; otherwise, the behavior is undefined." Having a pointer that points to no allocated memory for the reason of writing it out makes perfect sense. – Rasty Oct 29 '16 at 18:46