2

I have come across a piece of example code that uses pointers and a simple subtraction to calculate the number of items in an array using C++.

I have run the code and it works but when I do the math on paper I get a different answer.

There explanation does not really show why this works and I was hoping someone could explain this too me.

#include <iostream>
using namespace std;
int main() {
int array[10] = {0, 9, 1, 8, 2, 7, 3, 6, 4, 5};
int stretch = *(&array + 1) - array;
cout << "Array is consists of: " << stretch << " numbers" << endl;
cout << "Hence, Length of Array is: " << stretch;
return 0;
}

From: https://www.educba.com/c-plus-plus-length-of-array/

When I run the code I get the number 10.

When I print the results of *(&array + 1) and array by

cout << *(&array+1) << endl; cout << array << endl;

I get of course two hex address's.

When I subtract these hex numbers I get 1C or 28???

Is it possible that C++ does not actually give the hex results or their translation to decimal but rather sees these numbers as addresses and therefore only returns the number of address slots remaining?

That is the closest I can come to an explanation if some one with more knowledge than I could explain this I would be very grateful.

13
  • 2
    The problem is one of type. &array has type int (*)[10] (pointer to array of int[10]). When you add 1, the pointer arithmetic would give you the next pointer after the array. (one array of int[10] later). The different is 0x28 (e.g. 40 -- 10 int later) Let me know if that doesn't turn the light-bulb on and I'm happy to explain further. Focus on the type of each argument in *(&array + 1) - array Commented Dec 6, 2021 at 1:19
  • 1
    I suspect that you didn't correctly get 1C as the result of your subtraction. I must guess, since we can not see the numbers you subtracted. Commented Dec 6, 2021 at 1:24
  • In C++, you usually compute the number of elements in an array somewhat differently, on this general order: template <class T, std::size_t N> std::size_t size(T(&array)[N]) { return N; }. Commented Dec 6, 2021 at 1:31
  • the two address's I obtained were 0x7fd1943cb8 0x7fd1943cd4 when subtracting I got 1C I even ran it with a hex calculator. Commented Dec 6, 2021 at 1:32
  • 1
    Please don't post code in comment. Edit your question and add it there. Anyway, I managed to read it, in your second example your array has 7 elements, that's 7 x 4 or 28. In the first example you had 10 elements, that gets 40 Commented Dec 6, 2021 at 1:52

3 Answers 3

4

Let's take one step back and take it step-by-step to see if it will help. Continuing from my comment, the problem you are having difficulty with is one of type.

Let's take the array iteself:

int array[10] = {0, 9, 1, 8, 2, 7, 3, 6, 4, 5};

On access, an array is converted to a pointer to the first element in the array (e.g. the address of the first element) subject to caveats not relevant here. So when you say array, you have type int *, a pointer to the first element in array.

Now what happens when I take the address of the array? (&array in)

int stretch = *(&array + 1) - array;

When you take the address of the array, the result is the same address as array, but has type int (*)[10] (a pointer-to-array-of int[10]). When you add 1 to that pointer (recall type controls pointer arithmetic), you get the address for the pointer to the next array of int[10] in memory after array -- which will be 10 int after the first element of array.

So *(&array + 1) gives you the address to the next array of int[10] after array, and then dereference is only needed for type compatibility. When you dereference an int (*)[10] you are left with int[10] -- which on access gives you the address of the first element of that array (one after the original)

Think through the types and let me know if you have further questions.

Sign up to request clarification or add additional context in comments.

Comments

3

You forgot a small detail of how pointer addition or subtraction works. Let's start with a simple example.

int *p;

This is pointing to some integer. If, with your C++ compiler, ints are four bytes long:

++p;

This does not increment the actual pointer value by 1, but by 4. The pointer is now pointing to the next int. If you look at the actual pointer value, in hexadecimal, it will increase by 4, not 1.

Pointer subtraction works the same way:

int *a;
int *b;

// ...
size_t c=b-a;

If the difference in the hexadecimal values of a and b is 12, the result of this subtraction will not be 12, but 3.

When I subtract these hex numbers I get 1C or 28 ???

There must've been a mistake with your subtraction. Your result should be 0x28, or 40 (most likely you asked your debugger or compiler to do the subtraction, you got the result in hexadecimal and assumed that it was decimal instead). That would be the ten ints you were looking for.

Comments

0

I will try it with 5 items

#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
   int array[] {1,2,3,4,5};
   int items= sizeof(array)/sizeof(array[0]);
   cout << items << endl;                                                  
   int items2 = *(&array +1) - array;
   cout << items2 << endl;                                                 
   cout << array << endl;
   cout << *(&array +1) << endl;
   return 0;
}

root@localhost:~/Source/c++# g++ arraySize.cpp

root@localhost:~/Source/c++# ./a.out

5

5

0x7fe2ec2800

0x7fe2ec2814

using https://www.gigacalculator.com/calculators/hexadecimal-calculator.php to subtract the numbers from each other

I get

14 hex

20 decimal.

that fits with the 4 bytes to an integer.

thanx guys :)

this is an edit done on the 12th of december melbourne time ::

I have still had questions on this topic and something did not fit right with me about the entire route to counting array items via this code.

I found something I think is interesting and again would love to know why ( I shall try to explain it as best I can my self anyway)

*(&array + 1) is the question.

lets have a look at it.

as arrays are at there very nature in c and c++ only pointers to the first element in the array how can this work.

I shall use a small set of cout calls to see if I can find out whats happening.

#include <iostream>

using namespace std;

int main(int argc, char* argv[]){
        int array[] {1,2,3,4,5,6,7,8,9,10};
    int size {0};
    size = *(&array + 1) - array;
    cout << "size = *(&array + 1) - array = " << size << endl;
        cout << "*(&array + 1) = " << *(&array + 1) << endl;
    cout << "(&array + 1) = " << (&array + 1) << endl;
    cout << "(array + 1) = " << (array + 1) << endl;
    cout << "&array = " << &array << endl;
    cout << "array = " << array << endl;
    cout << "*(&array) = " << *(&array) << endl;
    cout << "*(array) = " << *(array) << endl;
    cout << "*array = " << *array << endl;
    return 0;
}

again this is off proot in my phone so still under root with no systemd.

root@localhost:~/Source/c++# g++ arrayPointerSize.cpp
root@localhost:~/Source/c++# ./a.out
size = *(&array + 1) - array = 10
*(&array + 1) = 0x7ff6a51798
(&array + 1) = 0x7ff6a51798
(array + 1) = 0x7ff6a51774
&array = 0x7ff6a51770
array = 0x7ff6a51770
*(&array) = 0x7ff6a51770
*(array) = 1
*array = 1

we see that as a pointer array can be called with * too derefernce the pointer and give the variable held in position [0] in the array.

when calling &array or reference too array we get the return of the address at the first position in the array or [0]. when calling just array we also get the address for the first position in the array or [0]. when calling *array the * is working as it does for pointers and it is dereferencing the arrays first position [0] to give the variable.

now things get a little interesting. *(array) also dereferences the array as is seen by its value being given as 1 in this instance. yet *(&array) does not dereference the array and returns the address to the first position in the array.

in this instance memory address 0x7ff6a51770 is the first spot in the array array = 0x7ff6a51770 and &array (reference to the pointer of the position in memory that is the first spot in the array) gives the same address 0x7ff6a51770.

it is also of note in this instance to remind us of the fact that *(&array) is also returning the first possition in the array and *(array) is not so we can not dereference a pointer too a position in memory as its variable is the position in memory.

if array and &array give the same answer as array is a pointer too the memory position in the first spot in our array and a reference to

this pointer.

why the different answer for (array + 1) and (&array + 1).

we get the memory address 0x7ff6a51774 for (array + 1) which is in line with an integer taking four bytes on my linux or

the addition of four bytes in memory past the first spot in the array (second array spot) but (&array + 1) gives a different answer.

if we follow the bytes and the code we see that (&array + 1) actually gives us the memory address four bytes after the end of the array.

so pointer too memory address add one gives the amount of bytes the variable type is past the memory address for the start of the array

and the reference to the pointer too the memory address add one gives the address the amount of bytes the variable type is after the last ?? spot in the array.

how then can array and &array return the same answer if (array + 1) and (&array + 1) do not.

it seems to me that the & reference when working with arrays overloads the + operator when doing arithmatic.

this would explain the difference in answers as straight &array has no operator too overload so returns the same answer as calling for

straight array

this small peice of code also shows that the use of pointers using *(&array + 1) is a very bad way to show a way to find array size with

pointers as really arrays are pointers and *(&array + 1) and (&array + 1) give the same result.

the heavy work was really being done by the reference operator &.

I may still be missing something here as I have used cout directly with the different experssions and being a stream it may

be limited in its ability to take advantage of what the reference operator is really doing when working with arrays.

I am still learning this language but I shall for sure keep this in mind as I dive deaper into c++.

I believe other than a few other trials with variables that the true answer will be found when reading the source for GCC g++.

I am not ready for that yet.

1 Comment

answer has been added too on the 12th of december.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.