2

I am learning how pointers work in C++, and am trying to iterate through an array using pointers and that confusing pointer arithmetic stuff.

#include <iostream>

int main()
{
    float arr[5] = {1.0, 2.0, 3.5, 3.45, 7.95};
    float *ptr1 = arr;
    for (int i = 0; i < 5; *ptr1 + 1)
    {
        std::cout << *ptr1 << std::endl;
    }
}

I declare an array of type float called arr[5]. Then I initialize a pointer variable *ptr1 holding the memory address of arr. I try to iterate it using *ptr1+1 (which gives no error), but then when I do std::cout << *ptr1 + 1 << std::endl I get an error:

operator of * must be a pointer but is of type float

Please help me fix this.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Shah Jacob
  • 137
  • 1
  • 9
  • 6
    I don't see that error with this code. What I do see is that your loop will never end since you never increment `i`; – jkb Sep 27 '21 at 23:17
  • Cannot reproduce: https://godbolt.org/z/f5a6v4Txa please provide a proper [mre] – UnholySheep Sep 27 '21 at 23:17
  • @jkb turns out the error is that I'm just incrementing the value at `ptr1`'s location and NOT the actual index – Shah Jacob Sep 27 '21 at 23:31
  • 1
    @ShahJacob "*I declare an array of type `float` called `arr[5]`*" - you are declaring an array of type `float[5]` named `arr`. "*I initialize a pointer variable `*ptr1` holding the memory address of `arr`*" - you are declaring a pointer of type `float*` named `ptr1`, and initializing it with the address of the 1st element of `arr`, due to [array-to-pointer decay](https://stackoverflow.com/questions/1461432/). "*I try to iterate it using `*ptr1+1`*" - that doesn't iterate anything. "*when I do `std::cout << *ptr1 + 1 << std::endl` I get an error*" - that statement does not produce that error. – Remy Lebeau Sep 27 '21 at 23:37

2 Answers2

3

In your loop, after each iteration, *ptr1 + 1 is dereferencing ptr1 to read the float it is currently pointing at, adding 1 to that value, and then discarding the result. You are not incrementing ptr1 itself by 1 to move to the next float in the array. You likely meant to use ptr1 += 1 instead of *ptr1 + 1.

More importantly, you are not incrementing i, so the loop will not terminate after 5 iterations. It will run forever.

The rest of the code is fine (though your terminology describing it needs some work).

Try this:

#include <iostream>
     
int main()
{
    float arr[5] = {1.0, 2.0, 3.5, 3.45, 7.95};
    float *ptr1 = arr;
    for (int i = 0; i < 5; ++i, ++ptr1)
    {
        std::cout << *ptr1 << std::endl;
    }
}

Online Demo

Though, a simpler way to write this would be to not use manual pointer arithmetic at all, just use normal array indexing notation instead:

#include <iostream>
     
int main()
{
    float arr[5] = {1.0, 2.0, 3.5, 3.45, 7.95};
    for (int i = 0; i < 5; ++i)
    {
        std::cout << arr[i] << std::endl;
    }
}

Online Demo

Or better, use a range-based for loop instead, and let the compiler do all the work for you:

#include <iostream>
     
int main()
{
    float arr[5] = {1.0, 2.0, 3.5, 3.45, 7.95};
    for (float f : arr)
    {
        std::cout << f << std::endl;
    }
}

Online Demo

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • @JuanR see my updated answer, I already mentioned that – Remy Lebeau Sep 27 '21 at 23:21
  • @RemyLebeau a little confused. what do you mean i'm assigning 1 to `ptr1`? i'm not assigning / using an equals sign *anywhere*. also why are you using both `++i` AND `++ptr1` – Shah Jacob Sep 27 '21 at 23:23
  • Your code worked, I marked it as the corrrect answer. However I don't understand why you're using two update statements and why `ptr1 + 1` works and not `*ptr1 + 1` – Shah Jacob Sep 27 '21 at 23:28
  • @ShahJacob I reworded my answer. – Remy Lebeau Sep 27 '21 at 23:29
  • @RemyLebeau much thanks Remy. I think I get it - by using `*ptr1` I'm actually accessing the VALUE at arr[0] (or the first element of the array's value) and not the index itself, so it can't ever update. However I'm a little confused why `++i` also needs to be included. – Shah Jacob Sep 27 '21 at 23:33
  • @ShahJacob Because you are using `i` to drive your loop, irrespective of what you do with `ptr1`. So you need to increment `i` as well to satisfy the `i < 5` condition. If you want to iterate using ONLY pointers, it would need to look more like this: `for(float *ptr1 = arr, *end = arr + 5; ptr1 != end; ++ptr1)` ([demo](https://ideone.com/8TKKxK)) – Remy Lebeau Sep 27 '21 at 23:39
  • how would you get the size of the array instead of hard-coding an int literal 5? i know arrays decay to the first memory address in the array, is that relevant? or is there a function? – Shah Jacob Sep 28 '21 at 00:03
  • @ShahJacob `size_t arr_size = sizeof(arr)/sizeof(*arr)`, or you can use [`std::size(arr)`](https://en.cppreference.com/w/cpp/iterator/size) which supports fixed arrays – Remy Lebeau Sep 28 '21 at 00:13
  • thanks remy. why do you need to divide by sizeof(*array) – Shah Jacob Sep 28 '21 at 01:30
  • @ShahJacob `sizeof(arr)` gives you the byte size of the whole array, whereas `sizeof(*arr)` gives you the byte size of a single element of the array. Dividing the first by the second gives you the number of elements in the array. The same value that `std::size()` will give you. – Remy Lebeau Sep 28 '21 at 01:40
  • @Jarod42 added, thanks – Remy Lebeau Sep 28 '21 at 14:25
  • maybe this is a 'dumb' question to imply this would be professional/production ready, but out of the 3 situations, which one is the most 'efficient' or 'reproducible?' is using pointer arithmetic, a regular for loop with index, or range based for loop the best? – Shah Jacob Sep 30 '21 at 20:52
  • @ShahJacob `arr[i]` for a regular array is just `*(arr+i)`, so it is basically pointer arithmetic. IMHO, the "most efficient" would probably be actual pointer arithmetic, as it can be written using only 1 incrementing variable, eg: `float *ptr = arr, *end = arr+5; while (ptr != end) { *ptr++ }` whereas the first 2 examples are incrementing 2 variables instead. A range-based `for` loop would be a close 2nd for efficiency, since it uses iterators not indexes, and iterators may or may not be actual pointers depending on implementation. – Remy Lebeau Sep 30 '21 at 21:29
  • what does `*(arr+i)` to? make use of pointer decay and get the value of the first element in the array? what's happening here? adding `1` to `arr` to move through the elements in the array and then `*` gets the value of it? – Shah Jacob Sep 30 '21 at 21:38
  • 1
    @ShahJacob "*what does `*(arr+i)` to? make use of pointer decay and get the value of the first element in the array?*" - the `i`'th element, not the 1st element. `arr` *decays* into a pointer to the 1st element, then that pointer is incremented by `i` elements, and then the pointer is dereferenced. "*adding `1` to `arr` to move through the elements in the array and then `*` gets the value of it?*" - I assume you meant `i` not `1`, but yes, that is exactly what is happening. – Remy Lebeau Sep 30 '21 at 22:02
2

You are actually adding 1 to the first float in the array but never increasing the pointer. And you don't increment the loop counter, therefore your program will run forever.

You need to correctly increase the pointer and also increase i:

#include <iostream>

int main()
{
    float arr[5] = {1.0, 2.0, 3.5, 3.45, 7.95};
    float *ptr1 = arr;
    for (int i = 0; i < 5; ++i, ++ptr1)
    {
        std::cout << *ptr1 << std::endl;
    }
}

Proof:

https://replit.com/@ichramm/PortlyMiserableNetframework#main.cpp

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
ichramm
  • 6,437
  • 19
  • 30