"Pointers make my head spin" etc ...

I've seen this comment in various formats over the years.

Why do so many people feel like its a problem wrapping their heads around pointers?

Is it only because of the compact and cryptic notation, or is it rooted in a deeper lack of understanding computers?

On this forum, may it just be that so many non-programmers want to make stuff?

travis_farmer:
Don't you know it is not polite to point? :wink:

If I recall, variables contain a value. pointers contain a variable.
Am I correct, or should my head be spinning?

~Travis

Spin away! :slight_smile:

travis_farmer:
clarification: it stores the address in memory of a variable.

~Travis

A pointer is a variable that explicitly stores a memory location, where data can be read from or written to.

Multiple pointers can point to the same location.

Behind the scenes, all variable names can be considered pointers, as they refer to locations in memory where the value of the variable is stored.

So, pointers do not point to variables, but they may point to the memory cells where the value of a variable is stored.

int i=5;   // value 5 is stored in memory somewhere, and known by name i

int *ptr=&i;  // ptr points to memory location for variable i, where 5 is stored

(*ptr)=6;  // updates data at memory location pointed to by pointer

In this example, the value of variable 'i' will change, but that's not because the pointer knows anything about the variable, only that they refer to the same memory cells.

:slight_smile:

travis_farmer:
ok, so I was close. :stuck_out_tongue:

admittedly, I didn't look up the first answer, but I did the second. and further admission, I didn't read the whole article, but I have bookmarked it for future digestion.

The simple definition also don't do much to convey what they really are or why they're so powerful (which is the part that's hard to wrap your head around).

Imagine a class where one of the member variables is a pointer to an object in that class. You can instantiate many objects and link them together to store large amounts of data, you can easily insert and remove objects from the list to keep them in order. Try to implement an array where adding another value keeps it in alphabetical order with zero performance penalty for sorting.

Now add more than one pointer to the class. You can have one pointer go to the next value alphabetically and the other go the next value according to some other criteria. You can keep the same data sorted by multiple different keys with no performance cost. With multiple pointers in a class, you can easily implement trees that have all sorts of rules to make them fast an efficient to traverse data.

Pointers are a very powerful concept, but it's hard to get ones head around just what they represent on a simple reading.

Rupert909:
Is it only because of the compact and cryptic notation, or is it rooted in a deeper lack of understanding computers?

For me the concept pointers (the addresses of memory locations at which data is stored) is trivially simple. But the ...ker that designed the C/C++ notation and its blatant inconsistencies made it very difficult to follow in that language. For example, why is byte myVal = 5; treated differently from byte myVal[1] = 5;

...R

Robin2:
For me the concept pointers (the addresses of memory locations at which data is stored) is trivially simple. But the ...ker that designed the C/C++ notation and its blatant inconsistencies made it very difficult to follow in that language. For example, why is byte myVal = 5; treated differently from byte myVal[1] = 5;

...R

Because one is a scalar and the other a vector (albeit a very short one)?

Robin2:
For me the concept pointers (the addresses of memory locations at which data is stored) is trivially simple. But the ...ker that designed the C/C++ notation and its blatant inconsistencies made it very difficult to follow in that language. For example, why is byte myVal = 5; treated differently from byte myVal[1] = 5;

...R

Just remember that array variables are poiinters. How hard is that? Assigning integer 5 to a pointer obviously is a dangerous thing to do.

:slight_smile:

Rupert909:
Just remember that array variables are poiinters. How hard is that? Assigning integer 5 to a pointer obviously is a dangerous thing to do.

:slight_smile:

You can treat them like pointers, however the reality is a little more complex.

An array is an array. An array id without a subscript can implicitly cast to a pointer, which points to the first element, but the array id is still an array.

Rupert909:
Just remember that array variables are poiinters. How hard is that?

That part is easy. What I don't understand is why they (whoever "they" are) decided that a simple variable name should not also be a pointer. Under the hood they are both memory addresses. Why treat them differently?

...R

Robin2:
That part is easy. What I don't understand is why they (whoever "they" are) decided that a simple variable name should not also be a pointer. Under the hood they are both memory addresses. Why treat them differently?

...R

Are you asking why "int a = 5;" isn't a pointer?

pYro_65:
Are you asking why "int a = 5;" isn't a pointer?

To be precise I am asking if int a[1] = 5; is treated as a pointer why is int a = 5; treated differently?

...R

int a[1] = 5;

The code above isn't valid. You need to use a brace-enclosed-initializer list.

But no, despite what @rupert909 mentioned, an array is not a pointer. It will cast to a pointer to the first element if used in an expression that accepts a pointer as an operand, however, it is most definitely an array and not a pointer.

Pointers become obvious if you program in assembly language for a while. (one of the reasons that some of us think that learning assembly language is still important, I guess!)

This is memory. Memory consists of a bunch of boxes, each one with an address, and each one having some data as contents.

        Addr    Data
         0       123
         1        42
         2        19
         3         0
         4       255
         5        'C'
         6        'A'
         7        'T'

Defining a variable is equivalent to attaching a name (or "label") to a memory location to make it easier to refer to in your program. Here, we have "answer = 42" and "char pet[] = "CAT";" This all happens in the compiler; the actual runtime binary doesn't know anything about the labels or variable names.

Label   Addr    Data
         0       123
answer:  1        42
         2        19
p:       3         0
         4       255
pet:     5       'C'
         6       'A'
         7       'T'
	 8	   0

we can make variable p be a pointer: "byte *p = 0;" Now, rather than having the value of a variable, p should have the ADDRESS of a variable. By convention, a pointer initialized to 0 (aka "null") is one that doesn't point at anything. But in the above you'll notice that 0 is actually a valid address (containing 123), so at the moment "*p" (read as "the contents at the pointer p" has 123, but address 0 isn't actually anything that we've made a variable, so that's probably some kind of error.
We can say "p=5;" or "p=pet;" or "p=&pet[0];" ("p gets the address of the first element of pet"), and then we have:

Label   Addr    Data
         0       123
answer:  1        42
         2        19
p:       3         5    ; points to pet
         4       255
pet:     5       'C'
         6       'A'
         7       'T'
	 8	   0

Now, "*p" will be 'C'. Note that there is nothing in the pointer to indicate exactly what it might be pointing at, or how long it is. It could be pointing at a character 'C', or at the beginning of string "CAT", or at some numerical value that happens to be the same as the representation of the letter C (67) The compiler tries to keep track of that for you, but again this disappears in the binary.
You can do math and stuff with the pointer. If you add 1, it will now have the value of 6, which is pointing at "A" instead of "C". You could subtract 2, and now it's pointing at itself (seems like a bad idea!)
You can pass p to a function, which would save space over passing all of "CAT".

And so on. That's sort of the basics of pointers. C has its own complications and niceities, like being able to point to things other than single bytes, or using array access syntax to access pointer values (and vis versa.) But chunks of memory with addresses is where you start.

pYro_65:
int a[1] = 5;

The code above isn't valid. You need to use a brace-enclosed-initializer list.

Apologies for the inadvertent error in the syntax.

But no, despite what @rupert909 mentioned, an array is not a pointer. It will cast to a pointer to the first element if used in an expression that accepts a pointer as an operand, however, it is most definitely an array and not a pointer.

In that case it makes even less sense for the compiler not to also cast an ordinary variable name to a pointer when it is "used in an expression that accepts a pointer as an operand"

...R

Robin2:
In that case it makes even less sense for the compiler not to also cast an ordinary variable name to a pointer when it is "used in an expression that accepts a pointer as an operand"

It is just a rule decided for that type and is explained in the section "standard conversions". I'll try my best to give it some sense though:

4.2 Array-to-pointer conversion [conv.array]
1 An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”. The result is a pointer to the first element of the array.

An array is unrelated to 'ordinary' variables, and it has its own features just as primitive types have their own standard "integral conversions".

Similarly though, you can get a pointer to an array by using the address of operator (&). This gives you an actual "pointer to array", whereas the standard conversion only gives you a pointer to the first element (you can also create a reference to an array).

To make things a bit clearer, the standard conversion for arrays is needed to access array elements. This is because the subscripting operator works with pointers (not actually an array specific operator). It has a clause in its description mentioning this:

The expression E1[E2] is identical (by definition) to *((E1)+(E2))

Its identical form (second one listed above) shows that either E1 or E2 must be a pointer as it is dereferenced to access the value. You can also do a proof of this.

The code below is accessing the second element of the array two different ways using the subscripting operator, showing that at least one operand must be a pointer:

  int array[5];

  int a = array[1];

  int b = 1[array];

So even though an implicit array to pointer conversion may seem strange, it is in fact needed to access elements of arrays.

You might be wondering what use is an array that isn't converted to a pointer (which is why many consider arrays to be simply pointers). Well it is because arrays provide more information than a pointer. Size/length info is lost once you have a pointer. You can maintain this with an array reference or array pointer:

I used a typedef to make the syntax a bit easier on the eye.

typedef int ArrayType[5];

void setup() {

  ArrayType array = {1,2,3,4,5};

  AddOneToArray(array);
}

void AddOneToArray( ArrayType &array ){

  for( auto &element : array ){  //Size info is maintained
    element += 1;
  }
}

void loop() {}

You could use an ArrayType* as the function parameter, you'd just need to dereference the pointer to return to the actual array.

This next example is a little more complex and shows two things, returning an array (reference) from a function, and also an unrelated example showing a real array pointer.

typedef int ArrayType[5];

class MyArray{
  public:
  
    //Allows conversion of class type to internal array type (returns a reference to array)
    operator ArrayType&(){
      return data;
    }

  private:
    ArrayType data;
};

void setup() {

  MyArray foo;

  //Use conversion operator provided by class, then access an array element:
  foo[4] = 1;


  ArrayType bar = {1,2,3,4,5};
  //Take pointer to array
  ArrayType *ptr = &bar;

  //Do something with array pointer
  (*ptr)[4] = 2;

}

void loop() {}

:sleeping: :sleeping: :sleeping:

...R

Robin2:
:sleeping: :sleeping: :sleeping:

...R

whatever

As some of you know I took a little time off to learn C++. We covered pointers and how they worked. After reading through these post I'm so confused. Hey teach help!!!

Naneen:
As some of you know I took a little time off to learn C++. We covered pointers and how they worked. After reading through these post I'm so confused. Hey teach help!!!

What is confusing you?

pYro_65:

typedef int ArrayType[5];

void setup() {

ArrayType array = {1,2,3,4,5};

AddOneToArray(array);
}

void AddOneToArray( ArrayType &array ){

for( auto &element : array ){  //Size info is maintained
    element += 1;
  }
}

Nice, didn't consider that array types remember their size, which they of course do (sizeof()).

Wasn't aware that C(++?) supports for-each type of loop syntax.

:slight_smile: