Is it necessary to use pointers in Arduino C ?

Is it necessary to use pointers in Arduino C ?

Generally it is never necessary to explicitly use pointers. Using arrays will use pointers, but in an implicit way.

For example, when you write "Hello, World" in a program, that creates a constant string that is actually a pointer to the 'H'.

Seems a strange question. It's a bit like "is it necessary to use the boot (trunk) in your car?"

It's necessary to use pointers when you have a coding problem that requires pointers.

...R

It's almost impossible to avoid them - any function name is pointer.

This is realy hard for me! Can you give an example in Ardunio-C how it works, with an output?

An example of what?

Your best bet is to just go with want you know and add explicit pointer references if you need them.

While function names "decay" into pointers, it is not necessary to know that to use functions. Just use them like the examples show.

persson121:
Is it necessary to use pointers in Arduino C ?

No. Frequently there is more then one method to solve a programming task, sometimes many methods. Pointers can result in very terse and (to some) elegant statements, but the same result more then likely can be performed without using pointers. I have so far avoided using them, but that is just a personal choice. I guess a valid question is, is there a C/C++ programming task that can only be done using pointers?

So learn and use them if your curious and want to completely master the language, but if you are able to solve your programming tasks without them presently don't feel you must use pointers.

Technically speaking,

Serial.print("this is a test");
// and
PORTB = 0x20;

use pointers, as do a bunch of things in the arduino core.
It ought to be relatively easy for a user to avoid needing to use explicit pointer variables, though.

Suppose you want to pass a variable to a function and you want the function to change that value and then send back a flag saying that it was (true) or was not (false) changed. Because most languages handle parameters passed to a function as "pass by value", the compiler actually makes a copy of your value, not the actual variable itself. So, your first attempt is:

void loop() [
   int val = 10;
   boolean flag = myFunction(val);
   Serial.println(val);
}
boolean myFunction(int v)
{
   if (v == 10) {
      v = 5;
      return true;
   }
   return false;
}

In the code above, you want to change the value to 5 if it is currently equal to 10 and tell loop() that you made the change by passing back true. However, when you print val in loop(), it's still 10. Again, the reason is because you passed a copy of val, not val itself. Now change it to:

void loop() [
   int val = 10;
   boolean flag = myFunction(&val);
   Serial.println(val);
}
boolean myFunction(int *v)
{
   if (v == 10) {
      *v = 5;
      return true;
   }
   return false;
}

In this case, the address of operator (&) in the function call tells the compiler: "Don't make a copy of val this time, send the address of where val is stored in memory." This is called "pass by reference". Notice that the function signature was also changed so it knows it was passed a pointer to val. What this means is that it knows where val lives in memory and, hence, can permanently change its value. Using the pointer (*v) in the assignment simply says: "Go to the memory address held in v and put 5 there." You are using a process called "indirection" to permanently change val, as confirmed by the print back in loop(). Just keep in mind that a valid pointer should only hold one of two things: 1) null, which means the pointer points to nothing useful, or 2) a memory address.

@econojack, that is a very contrived example and I suspect you could code for a lifetime without needing to do that.

If the O/P is scared of pointers s/he can rely on being able to write many complex Arduino programs without needing to use pointers explicitly. The fact that the compiler uses pointers under the hood is irrelevant.

Having said that the concept of pointers is very simple - it's just the C/C++ script conventions that I find confusing. They could so easily have had functions called addressOf() and valueAtAddress() etc. (And I guess you could create them with macros).

...R

Pointers are (arguably) the most powerful part of C. If you get serious about coding you won't be able to write more than 10 lines of code without using one.

That said you can do just fine without them and you certainly don't have to muddy the "learning C" waters by introducing them too soon.


Rob

There is nothing particularly scary about a 'Pointer'. What is one? Well, it is simply an address in memory. An example:
Imagine this is a 32byte memory - there are 32 boxes, each can store a byte.

[   ][   ][   ][   ][   ][   ][   ][   ]
[   ][   ][   ][   ][   ][   ][   ][   ]
[   ][   ][   ][   ][   ][   ][   ][   ]
[   ][   ][   ][   ][   ][   ][   ][   ]

so lets say we do the following:
byte a = 10;

This tells the compiler to allocate a byte of memory (one box) to the variable named 'a' and store the value 10 in it, so what does our memory look like now? (lets pretend that the compiler says to allocate box 3)

[   ][   ][ 10][   ][   ][   ][   ][   ]
[   ][   ][   ][   ][   ][   ][   ][   ]
[   ][   ][   ][   ][   ][   ][   ][   ]
[   ][   ][   ][   ][   ][   ][   ][   ]

Now lets say we want an array of 6 characters (bytes) to store "Hello". So we would do:

char helloString[6] = "Hello";

The compiler for example allocates this starting at say address 16 (just a number plucked out of my head). So our memory looks like this:

[   ][   ][ 10][   ][   ][   ][   ][   ]
[   ][   ][   ][   ][   ][   ][   ][   ]
['H']['e']['l']['l']['o'][  0][   ][   ]
[   ][   ][   ][   ][   ][   ][   ][   ]

Notice that because there are 6 bytes for this variable they fill up 6 sequential boxes.

Trouble is, in C++, an array isn't really an object in its self, it is really a collection of 6 separate object, 6 characters in this case. So how would you describe it? How could you identify it in memory.

Well, it is stored at address 16, and has a length of 6.

Now say you wanted to find out the address of it - next time you run the program it might be somewhere else - remember I said I picked the address at random. So really we need some code to find out where it is.

char* address = &helloString[0];

But what does that mean? It looks a bit of a mess doesn't it. But in reality it is quite simple. It basically says, go to the first element in the array (helloString[0]) and find the address of that (&). Finally, save the address to a variable named 'address'. That is really all there is to it. Pick an element, get its memory address.

There is one last thing which makes it a "pointer" rather than an "address", and that is a description of what it is an address to. You could get the address of an integer, you could get it of a byte, in fact you can get one of any type your heart desires, afterall they are all stored in memory.
You will notice that I have declared the new variable as a char* which basically says, this variable stores an address () of a character (char). Put that together and you get char. If it were an address to an int, you would write int* and so forth.

Of course now that we have created a new variable named address, it will also have to be stored in the memory just like any other variable. So our memory may now look like:

[   ][   ][ 10][   ][   ][   ][   ][   ]
[   ][   ][   ][   ][   ][   ][   ][   ]
['H']['e']['l']['l']['o'][  0][   ][   ]
[  0][ 16][   ][   ][   ][   ][   ][   ]

What is the address of the array? well, in this case you remember it is 16, so you can see [0][16] in the memory.

But why is it [0][16] and not just [16]? Well, it is a pointer to an address in memory, so it basically has to be a variable large enough to store the full range of memory addresses. For an Arduino Uno you have 2048 bytes of RAM, so you need 11bit pointers to store the full range of memory. So what is the smallest multiple of 8 which is larger than 11? 16. So for an Arduino a pointer is 2 bytes.

The final step, now that we know the address of our variable, we want to be able to access it. Say for example we want our string from before to say "Jello". So we need to change the first element to be 'J'.

*address = 'J';

We know 'address' currently stores the address of the first element in the array, so what we need to do is say, store the value 'J' (='J') at the address (). The ____ is our way of saying this - it says read or write to the address that this pointer points to.
So we now have:

[   ][   ][ 10][   ][   ][   ][   ][   ]
[   ][   ][   ][   ][   ][   ][   ][   ]
['J']['e']['l']['l']['o'][  0][   ][   ]
[  0][ 16][   ][   ][   ][   ][   ][   ]

Hopefully that makes things a bit clearer. Any questions? feel free to ask.

(p.s. "Arduino C" is really just "C++", so much of what you can do in C++ you can do on an Arduino. There are a few things like the boost library which don't exist on Arduino, but you will never need them).

1 Like

(lets pretend that the compiler says to allocate box 3)
Code:
[ ][ ][ 10][ ][ ][ ][ ][ ]

Let us, instead, pretend that the compiler says to allocate box 2.
It makes future arguments about indices less contentious.

@Robin2: I never said it wasn't contrived. I was simply trying to show him how pointers work and explain terms he probably read while trying to figure things out. Having taught university-level programming courses at a Big 10 university for almost 30 years, I have pretty good evidence that, sometimes, contrived examples help the penny to drop for the beginning student better than real-life examples.

If you've stood in front of 120 pairs of deer-in-the-headlights eyes when discussing pointers and have a better way to explain it, have at it.

I'm always learning more about programming and lately I've been trying to move more to C++ from C. When I read the title of this thread my first thought was Arduino is C++ and C++ can pass by referenece.

Is this not the C way?

void loop() [
   int val = 10;
   boolean flag = myFunction(&val);
   Serial.println(val);
}
boolean myFunction(int *v)
{
   if (*v == 10) {  // my compiler complained without the * here 
      *v = 5;
      return true;
   }
   return false;
}

Is this the C++ way?

void loop() [
   int val = 10;
   boolean flag = myFunction(val);
   Serial.println(val);
}
boolean myFunction(int& v) // C++ pass by reference.
{
   if (v == 10) {
      v = 5; // no need to use * anymore
      return true;
   }
   return false;
}

That seems easier to me. I'm a self taught programmer and I've always struggled with pointers and managed to avoid them often. The problem is that to avoid them often means more global variables.

C++ can pass by referenece.

Is this not the C way?

Correct - it isn't the C way.
C doesn't have references, it's a key difference between C and C++.

econjack:
@Robin2: I never said it wasn't contrived. I was simply trying to show him how pointers work and explain terms he probably read while trying to figure things out. Having taught university-level programming courses at a Big 10 university for almost 30 years, I have pretty good evidence that, sometimes, contrived examples help the penny to drop for the beginning student better than real-life examples.

If you've stood in front of 120 pairs of deer-in-the-headlights eyes when discussing pointers and have a better way to explain it, have at it.

We are at cross purposes. My intention in writing my post was to suggest that the OP could safely ignore pointers (rather than wasting his time and mine trying to explain them until it was really necessary).

Also, as I tried to say earlier, it's not the concept of pointers that is the problem - it's the arcane way that the C/C++ developers decided to refer to them - as if there was some value using a single character ("*") instead of an easily understood word such as "addressOf()".

...R

1 Like

Except in C, it is not possible to make a function return different types, and a void * is different than byte * which may be different than *(f())

as if there was some value using a single character ("*") instead of an easily understood word such as "addressOf()".

Why yes, there is! Or we'd be programming our Arduinos in COBOL.
I've used a language where ALL variables were pointers, and you had to used a prefix character to get at the value. (That seems to have faded to well-deserved obscurity...)

Pointer are easier to understand if you've used an assembly language. Perhaps modern HLLs spend entirely too much making their data NOT look like a big uniform glob of memory bytes...

westfw:

as if there was some value using a single character ("*") instead of an easily understood word such as "addressOf()".

Why yes, there is! Or we'd be programming our Arduinos in COBOL.
I've used a language where ALL variables were pointers, and you had to used a prefix character to get at the value. (That seems to have faded to well-deserved obscurity...)

Pointer are easier to understand if you've used an assembly language. Perhaps modern HLLs spend entirely too much making their data NOT look like a big uniform glob of memory bytes...

I'm afraid I don't understand the reference to Cobol. Is there some technical reason for mentioning that rather than Fortran, Basic or Python?

I started learning programming on IBM360 assembler language (and perhaps I should have chosen programming for a career, but I didn't, it's just a hobby).

...R