0

I have been wondering about pointers and can't find a source explaining them with details.

For example. Given an array int a[3] There is a pointer pointing at 4 locations? It starts as *[a+0] and points at address of a? Then what does it do next? Int is minimum of 16 bites, so it needs to read 2 bytes, but every byte is given an address.

Does it mean that for a[0] the pointer points at the beginning address, then the program reads sizeof(int) bytes starting at the given address?

What would it do the next? Would it stop reading, give the result and for a[1] would it point at address of &a+1*sizeof(int). It would start reading at address of (&a+2(as 2 stands for already read addresses of 2 bytes)), start reading, so it would read another 2 bytes and on and on?

I can't quite understand these concepts.

PS: String consist of unsigned char which are 1 byte elements. The post you mentioned doesn't explain what happens with elements larger than 1 byte. It also doesn't explain exactly what the program does beside "here is a string the program reads from memory". I assume that I am right, but nonetheless the title you mentioned is far away from what I asked about. (since somebody wrote this already, one address stands for one byte)

  54   55   56   57   58   59   60   61   62   63   64   65   66   67   68   69
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|----|----|----|----|----|----|    |    |    |    |    |    |    |    |    |    |
0----+----01---+----12---+----2----+----+----+----+----+----+----+----+----+----+

I specifically asked if int a[2] means that the pointer first: Points at memory address (54), the program reads data from 2 following addresses (54 to 54 as int takes 2 bytes), then the pointer points at address 54+2, the program starts reading from address range <56,57>. Then again, the pointer points at starting range of 58, the program reads at address of <58,59>

Is this logic correct? It isn't a string ended up with NULL. My guess to strings is that the program would access memory byte's address by byte's address and read the values till it found NULL.

Arrays aren't strings.

  • `a` points to just one location, which is the "start" of the first `int`. `a[1]` is read from `a + 1 * sizeof(int)` (which may be `a + 4` or `a + 8` etc, it's fixed at compile-time), and so on with `a + 2 * sizeof(int)`. If you had an array of `foo`s, `a[1]` would be `a + sizeof(foo)`. – hnefatl Apr 10 '18 at 21:02
  • Possible duplicate of [How do pointer to pointers work in C?](https://stackoverflow.com/questions/897366/how-do-pointer-to-pointers-work-in-c) – XCS Apr 10 '18 at 21:03
  • Accessing `a[2]` doesn't involve three steps, it only involves 1 - `a + 2 * sizeof(int)` is accessed, in your example `a + 4` or `58`, and the value is read from bytes in the range `a + 2 * sizeof(int)` inclusive to `a + 3 * sizeof(int)` exclusive (58 and 59). Arrays **are** strings - in fact, they're both [effectively just pointers](https://stackoverflow.com/questions/1641957/is-an-array-name-a-pointer). Strings just have a `\0` on the end by convention, and the type of element (`char` vs `int` vs `foo`) only matters in the `sizeof` additions. – hnefatl Apr 10 '18 at 21:52

1 Answers1

1

Consider

int a[3] = {};
int b[300] = {};

These 2 arrays are "similar" in that they contain values of int and are different in these two major regards:

  1. They are of different "size" - that is the memory they point to is reserved with different amount for each. The first array points to a memory that is reserved to hold at least 3 int values. However that is the minimum allocated memory (in this case - on a stack, so most likely it is also a precise amount of memory allocated for it as well)
  2. They point to different addresses in memory (again - in this case they are both allocated on a stack but it is still a RAM)

You can just as easily take an address of the first element of either array:

int * p = a;
p = &a[0]; // same as above
p = b; // now p points to the first element of the second array

When you perform an indexing operation what the compiler does is: it takes the address of the first element and increments it by a value that is equal to the index times the size of each element (if there's no padding due to alignment, of course). In essence the compiler is doing this:

b[1] = 1;
*(p+1) = 1; // same as above
uint8_t * c = reinterpret_cast<uint8_t*>(p); // WARNING! Explanation follows

The last line will cause the compiler to reinterpret the pointer differently and "the same" address arithmetic "suddenly" works differently:

c[1] = 1; // this is NOT the same as b[1] = 1

In this case the compiler will only "move" the pointer 8-bits (not 16 or 32 bits, depending on your platform's sizeof(int)) and end up in the middle of that first int element of array b. Granted this can be useful (especially when dealing directly with hardware) but is super-duper-puper non-portable and you should avoid doing so at all times!

This is admittedly not a comprehensive answer but I was not aiming to provide one as the topic is very vast and there are plenty of resources on the Web that can provide you with many more details on this subject

YePhIcK
  • 5,816
  • 2
  • 27
  • 52
  • This is a valuable answer. I didn't know about this type. Sadly, I would also learn about how the elements are read from the addresses, but nontheless your answer is helpful. Especially this "c[1] = 1; // this is NOT the same as b[1] = 1". It would move by 8 bits instead of 16 and point at a totally different address even though it started at a good one (that's why [1] right?). (I upvote, but can't make it visible without 15 rep). –  Apr 10 '18 at 22:10
  • Yes, the `c[1]=1;` was specifically chosen to "land" in a middle of a byte, making it invalid (for the purposes of this example). I'd suggest you spend some time on YouTube watching C++ address management - that will provide you with hours of videos (of varying quality, admittedly) that will greatly improve your understanding. The topics I didn't cover: memory performance, contiguous vs random-access, arrays of objects, objects' ownership, C++11's `std::unique_ptr` and `std::shared_ptr`, "short-string optimization" in STL, and many-many more – YePhIcK Apr 10 '18 at 22:17