This may be basic 101 stuff everyone else knows. This might not be the right part of the forum to post this, but I tried to choose carefully.
I learned a lesson the hard way. As debugging on the Arduino isn't quite like Visual Studio.NET (it's not easy to follow variable values as the code executes), I'll pass this along in case it helps anyone.
I have a function, I want it to modify some of the values I pass into it. Passing in pointers is fairly well documented. The problem I had was in changing the values using the increment/decrement operators.
Inside the function we use something like *foo or *bar to refer to the value. *foo = *foo + 1; works and if *foo pointed to a value of 5 it will now point to a value of 6. But *foo++ doesn't change the 5 to 6, it changes what the pointer points to. To change the 5, in this example, you need to do this: (*foo)++;
I had been passing in values and for some I used the *var = *var + 60; and got the expected results. But when I just needed to change the value by 1, I tried *var++; and got...unexpected data. Searching online I first ran across a Microchip article which suggested (*foo++) but that didn't work for the Arduino implementation of C++.
Everything was great when the conditions only called for the modification of those variables I used the *foo = *foo + value; but when the conditions changed to require the modification of variables for which I used *foo++;, things went south. That lack of knowledge cost me about an hour.
Thank you for that. I had to read that a few times. I think I've got it.
Line 3 actually does this:
int v2 = v1;
ptr++;
Where we might be expecting it to yield v2 == 6 instead it's v2 == 5 and now the pointer is incremented to point at...whatever, which, as you said, probably is invalid.
One thing I wasn't recognizing is that the parentheses were still doing what they'd do in any other code: manually setting a precedence: dereference foo then foo++.
I see now why the *ptr++ would be very helpful for navigating an array. I also, as I was side-checking what I was thinking and writing, found that the ++ can be at the beginning to do it first before the value is used. I didn't know that. Yeah, I don't know much.
Thank you for this. It took a hot minute to grasp what @J-M-L had written but that time made it easier to understand what you've written.
I very much see how that would be a slick way to bang through a number of data to copy. But you make a very good point about the forced dereference: the "+=" is clearer than the overridden precedence.
Thank you for the reply. I'm going to have to learn a bit to understand this. In my head, "by pointer" and "by reference" are the same thing. Obviously, from your post, they're not the same thing, hence why I need to learn something.
Here is the function heading to which I am passing pointers:
void AdjustOpenCloseTimes(int* OpenTH, int* OpenTM, int* CloseTH, int* CloseTM, unsigned long int SR, unsigned long int SS, int SRO, int SSO)
I think now that I don't know enough about the use of * and & and pointers and references to intelligently articulate anything further. It's past 2AM...I'm going to bed and I'm going to go read about those over coffee in the (later) morning. Then I'll post back.
In C++, passing by pointer allows a function to access and modify the original variable through an explicit address using * and & operators, while passing by reference provides direct access to the original variable without requiring explicit dereferencing. Note that a pointer can be set to nullptr to indicate it points to nothing, whereas a reference must always alias a valid object and cannot be null.
you are missing the types. The & just informs the compiler that you want to pass by reference
void AdjustOpenCloseTimes(int& OpenTH, int& OpenTM, int& CloseTH, int& CloseTM, unsigned long int SR, unsigned long int SS, int SRO, int SSO)
{
...
}
and of course, since they are references and not pointers, in the function you refer directly to OpenTHor OpenTM etc when you want to read or modify their content. No need to dereference with a *.
Perhaps for this simple application. Although references do provide a couple safety features even here … As mentioned, you are always assured that a reference is bound to a valid object (verses the possibility of being passed an invalid pointer). And, with a pointer, the function could access unintended memory by doing pointer arithmetic (not possible with a reference).
However, references are indispensable for implementing more advanced C++ features. Perhaps the most of important being Operator Overloading.
You can think of the situation as a Venn Diagram where the possible uses of pointers and references intersect. In some applications you can use either. But there are some applications where only either one or the other will work.
That’s what meets the eyes at first. As you dig into C++ you’ll see that references offer safer, clearer, and semantically stricter indirect access than pointers, which makes them the default choice unless nullability or reseating is explicitly needed (Once a reference is bound to an object, it can’t be reseated to another object, which makes the code safer and more predictable versus pointers which can be reassigned).
Okay, so, I lied...I got in bed and read about pointers and references before I went to sleep...a little obsessive.
I see now how they are different but it's going to take a bit of time to let that really sink in. I very much see the difference between their ability to be null or not and the need or not to explicitly dereference them.
In the code example provided by @gfvalvo I like the "var *= 3;" clarity (to me) of not having an explicit dereference.
There may (or may not...seems to be some variance) in whether or not an address storage space is used for a reference.
The lines of code I posted are from a working sketch. The &OpenTimeHour etc are in the function call not the definition.
I see now the difference but, again, it's going to take a bit of time for the understanding to really settle in. To bring that back to clarify my original post about dereferencing a pointer with the post-increment operator: where I point out the need to use () in (foo*)++, if this was passed by reference I would simply use foo++;, correct? If so, that would have eliminated my (now silly to me) parenthetic overriding of precedence.
As I was proofreading...in one thread I started someone pointed out best practices and in some reading about the pointers/references it was stated to use references when possible and pointers when they aren't. Is this maybe more a matter of best practice, choosing between pointers and references?
The point about the safety of a reference always pointing to a valid object is a good one and maybe sufficient reason alone to use them when possible, at least for me. Watching garbage show up in the Monitor while the sketch doesn't do what is intended because of an accidental (misunderstanding of) incrementing a pointer instead of the target value is confusing. A reference would have prevented that in my case.
I don't like references, because it seems like it would be so simple to modify a structure that the caller function didn't intend to be modified. Having to explicitly pass pointers is a big "hint" that your data may be subject to change...