Pointers, references (and types) ... For the sake of knowing how it works!

Hi guys!
I am a n00b with arduino, never programmed C++, but I've been C programming for a while. 8)
My project is to make my arduino alarm clock, so that I get to learn the basics of arduino, and I will have the BEST alarm clock in the world!! (and I don't have to buy a new stupid one :stuck_out_tongue: ).

So here's the fact: I am using arduino Time library, got through README and Time.h and found:

typedef struct  { 
  uint8_t Second; 
  uint8_t Minute; 
  uint8_t Hour; 
  uint8_t Wday;   // day of week, sunday is day 1
  uint8_t Day;
  uint8_t Month; 
  uint8_t Year;   // offset from 1970; 
} 	tmElements_t, TimeElements, *tmElementsPtr_t;
/* ...  */
void breakTime(time_t time, tmElements_t &tm);  // break time_t into elements

So I used them:

#include <Time.h>
/* ...  */
tmElements_t alarm = { 0, 0, 0, 0, 0, 0, 0 };
/* ...  */
void setup() {
  /* ...  */
  // sets default alarm time & date
  breakTime(305712000, &alarm);
  // unix time 305712000 is Sept 9 1979, 8:00 -- MY BDAY!
}

But, :astonished: :astonished: when I tried compiling, I got this error:
TestAlarmClock.cpp: In function ‘void setup()’:
TestAlarmClock:211: error: invalid initialization of non-const reference of type ‘tmElements_t&’ from a temporary of type ‘tmElements_t*’
/usr/share/arduino/libraries/Time/Time.h:111: error: in passing argument 2 of ‘void breakTime(time_t, tmElements_t&)
I double checked definitions and declarations, and, as I though there was no error, I retried! :fearful: :fearful:
Still same error. I read compiling error more carefully, and removed trailing & on second argument. OK ! :relaxed:
But, as I can't stand not understanding what goes on, specially in programming ]:), I posted this.
So... What is this "magic cast" that turns a struct variable into a pointer?
What am I missing? Is it C++ related? As far as I know, writing a correct C code will work in a C++ source...
Is it a correct C source?? :roll_eyes:

Again...

See my examples and new libraries here..
http://arduino.cc/forum/index.php/topic,51802.0.html

My examples work if you have the RTC.

Using this RTC

Thanks for the reply, but I still don't get it.
Post you linked does not seem related, giving it a quick look (and I am not using an RTC for now)...
My question is not related to Time library, but to programming syntax..
Seems to me I am missing something (probably dumb) on the definition of the struct.
Why alarm type "becomes" tmElements_t * ?? I expected a tmElements_t?

What was that again for?

breakTime takes a time_t and a reference, not a pointer, to a tmElements_t.

StriDer99:
Why alarm type "becomes" tmElements_t * ?? I expected a tmElements_t?

Oh well, I am messed this up..

AWOL:
breakTime takes a time_t and a reference, not a pointer, to a tmElements_t.

This makes sense!
so you're saying that breakTime definition wants a "simple" variable!
I guess this is C++, almost equals to C void breakTime(time_t time, tmElements_t tm)
but with the & preceding tm allows to keep changes made inside breakTime outside its scope?
Wait, isn't its value change kept 'cause declared as global?
(BTW I realize now I've never seen an "&" inside a function declaration/definition...)
Is it allowed in some C standard?
Or it's just a C++ way of pointing out that the argument must be a reference? Is it mandatory?

Thanks anyways AWOL

... I'll find out googleing...

There are basically 3 methods of passing parameters into a function. You can pass byVal, byRef, or pass a pointer.

void func1(int z){
  z++;
}

func1 passes it's parameter z byVal. In other words, it's passing the Value into the function. This function as it is accomplishes nothing. If I call it as follows:

int x = 500;
func1(x);
Serial.println(x);

The println is going to output 500, because I passed the value of x into the function, not x itself. Even if x is global, you will not be modifying x because you're only passing in it's value.

void func2(int &z){
  z++;
}

Now func2 passes it's parameter byRef, meaning you are passing in a reference to the actual variable. The call itself will look the same, but the behavior is quite different.

int x = 500;
func2(x);
Serial.println(x);

This code will now output 501. Here we are passing a reference to x into func2, and thus the value of x will get modified as a result. As I said though, how you call the function is identical though.

And the final method is passing in a pointer to x. The function declaration will look like this:

void func3(int* z){
 (*z)++;
}

So this function looks quite a bit different, and it is also called differently as well.

int x = 500;
func3(&x);
Serial.println(x);

As with passing byRef, this will also modify the value of x as well and output 501. But you call the function differently, and you also manipulate the z variable inside the function differently, because it is a pointer and behaves differently.

There is no difference in any of this behavior with regards to C vs C++.

@jraskell: Nice explanation by examples, thanks for taking time to reply, and try to focus on questions. I really appreciated!
As I said in first post, I have good skills in C programming but I know little about C++, apart that is directly derived by C, and, even if a "medium" level language, supports object oriented programming.
I am a really pedantic programmer. I strongly believe meticulous coding and deeply understanding of what's going on is key to achieve good quality code instead of code that (most of times) just works. I've been taught like that and it's part of my personality. I also like sharing what I know and I am sure of... So I hope this helps someone...
Btw:
You make some good points, but I would like to get deeper into a couple of them.

jraskell:

int x = 500;

func1(x);
Serial.println(x);


The println is going to output 500, because I passed the value of x into the function, not x itself. Even if x is global, you will not be modifying x because you're only passing in it's value.

You are right: it will output 500. However, another question comes to my mind: what if "x" if also the name of the parameter the funtion? Something like this:

int x = 500
void func1(int x) {
  x++;
}
[ ... ]
void loop() {
  func1(x);
  Serial.println(x);
}

It would always :astonished: output 500 (I tried)!!!! This is same in C, because internal (automatic) variables, including parameter names, will always hide external ones.
Is it true also for C++?... I strongly suspect it by arduino's behaviour: am I right?

jraskell:
There is no difference in any of this behavior with regards to C vs C++.

I must disagree :stuck_out_tongue: :stuck_out_tongue: . C has nothing similar to C++ reference type. It only has pointers and "normal" variables (reference = value in a few words). When passing a parameter reference, it means that you are passing the variable's value using the name (reference) of the variable. '&' operator literally means "the address of the variable". It cannot be used in declarations as a left value. SOmething like int &v it's not compiling. If you want a pointer to that variable, you use &v. The only way to modify and keep modified a variable's value outside its scope is using pointers. For example:

// outputs 1, 2, 3, 4 ... 
// C++ passing value by reference modifies output
int i = 0;
void funct(int &x) {
  x++;
}
void setup() {
}
void loop() {
  funct(i);
  Serial.println(i);
}

//Pointers C style
int i = 0;
void funct(int *x) {
  (*x)++; //referencing pointer, i want the value of the variable 
}
void setup() {
}
void loop() {
  funct(&i); //deferencing variable, I want the address (pointer) of the value.
  Serial.println(&i);
}

Nite! ]:smiley:

StriDer99:
It would always output 500 (I tried)!!!! This is same in C, because internal (automatic) variables, including parameter names, will always hide external ones.
Is it true also for C++?... I strongly suspect it by arduino's behaviour: am I right?

Yes, using a parameter hides any global variable of the same name. With various warnings turned on (or using lint) you get warnings about that. "shadowed" variables I think they call them.

jraskell:
If you want a pointer to that variable, you use &v. The only way to modify and keep modified a variable's value outside its scope is using pointers.

No, this code of yours demonstrates that:

int i = 0;
void funct(int &x) {
  x++;
}

void setup() {
  Serial.begin (115200);
}

void loop() {
  funct(i);
  Serial.println(i);
}

It outputs an incrementing number. So that "modifies and keep modified a variable's value outside its scope" without using pointers. And it looks better than passing addresses, and dereferencing them all the time.

It cannot be used in declarations as a left value.

Yes it can. This compiles:

const int i = 42;
const int & b = i;

void setup() {
  Serial.begin (115200);
  Serial.println (b);
}

void loop() {
}

And it prints "42".

Where's my towel!

@Nick
O well[quote author=Nick Gammon link=topic=56315.msg404308#msg404308 date=1300950860]

StriDer99:
If you want a pointer to that variable, you use &v. The only way to modify and keep modified a variable's value outside its scope is using pointers.

No, this code of yours demonstrates that:

int i = 0;
void funct(int &x) {
  x++;
}

void setup() {
  Serial.begin (115200);
}

void loop() {
  funct(i);
  Serial.println(i);
}

It outputs an incrementing number. So that "modifies and keep modified a variable's value outside its scope" without using pointers. And it looks better than passing addresses, and dereferencing them all the time.

StriDer99:
It cannot be used in declarations as a left value.

Yes it can. This compiles:

const int i = 42;
const int & b = i;

void setup() {
  Serial.begin (115200);
  Serial.println (b);
}

void loop() {
}

And it prints "42".
[/quote]
:zipper_mouth_face: Did you try the code before posting? ...There's always something to learn.. :zipper_mouth_face:
I was talking about C and not C++.... pointing out that there are actually some differences between C and C++, as C has no reference data type: only variables and pointers. Try compile this, using a c complier!

#include <stdio.h>
int x = 0;
void increment(int &z) {
  z++;
}
int main() {
  int i;
  /* doing only 10 cycles so the programs stops by itself */
  for (i=0;i<10;i++) {
    increment(x);
    printf("x = %d\n", x);
  }
  return 0;
}

If using linux, gcc myCsource.c would do it. Well it DOES NOT compile, as complaining a sysntax error, cause function is declared using a reference type parameter void incremement(int &z) that does not exist in C.
Another C example:

#include <stdio.h>
int v = 0;
int &r = v;
void increment(int &z) {
  z++;
}
int main() {
  int i;
  /* doing only 10 cycles so the programs stops by itself */
  for (i=0;i<10;i++) {
    increment(r);
    printf("x = %d\n", x);
  }
  return 0;
}

It will fail compiling at line 3, int &r = v; syntax error caused by using & operator in a left value.

Last example:

#include <stdio.h>
int v = 0;
void increment(int *z) {
  z++;
}
int main() {
  int i;
  /* doing only 10 cycles so the programs stops by itself */
  for (i=0;i<10;i++) {
    increment(v);
    printf("v = %d\n", v);
  }
  return 0;
}

This one compiles, giving a warning at increment(v) line, warning: passing argument 1 of ‘increment’ makes pointer from integer without a cast. If you run it, won't increment ouput v. If you are unlucky, will crash for a segmentation fault.

Anyways I see this discussion pointless, if you are not willing to learn C, sticking to C++ (that could be a reasonable choice dealing with arduino).
But another question comes to my mind: besides arduino IDE, can I use a C++ source to program arduino, or only "plain" C source?
Does arduino support "low level" C++ or only C?

Arduino's support of C++ is a mixed bag. For example, Arduino does NOT provide a new or delete operator. It also doesn't provide any of the streaming operators/classes (as embedded devices typically don't provide even close to the same environment PCs provide).

It's support of the C standard is closer to being complete, but still not exactly 'complete'. But again, that's largely due to embedded device I/O vs PC I/O.

And thanks for correcting my previous claim. It's been too long since I've programmed in a C only environment.

StriDer99:
Did you try the code before posting? ...There's always something to learn.. :zipper_mouth_face:
I was talking about C and not C++.... pointing out that there are actually some differences between C and C++, as C has no reference data type: only variables and pointers. Try compile this, using a c complier!

Oh, I'm sorry, I thought we were talking about the Arduino as this is the "Arduino Forum :: Using Arduino :: Programming Questions" forum. Of course I compiled it - on the Arduino - or I wouldn't have made that claim.

The Arduino IDE turns your sketch into a .cpp file (hold down Shift whilst clicking the Verify button to see that). A lot of the libraries are implemented in C++. So I don't really see the point of worrying about what straight C might or might not do.

Anyways I see this discussion pointless, if you are not willing to learn C, sticking to C++ (that could be a reasonable choice dealing with arduino).
But another question comes to my mind: besides arduino IDE, can I use a C++ source to program arduino, or only "plain" C source?
Does arduino support "low level" C++ or only C?

Well, many people learn C and then "upgrade" to C++. I don't know anyone who would willingly go backwards, except to work on old code. Again, if you look at the output of the verbose compile, you will see that some libraries are C, some C++.

For example, Arduino does NOT provide a new or delete operator.

It depends what you mean by Arduino here. The language does. This example compiles (in the Arduino IDE) and runs OK:

class myObj
{
public:

  myObj () {};  // default contructor 
  
  void * operator new (unsigned int size)
  {
    return malloc (size); 
  };

  void operator delete (void* ptr)
  {
    if (ptr)
      free (ptr);
  };  

  void hello () { Serial.println ("hi there!"); };
  
};


void setup() {
  Serial.begin (115200);
  
  myObj * test = new myObj;

  test->hello ();
  
  delete test;
}


void loop() {

}

I used new, delete, and used them to allocate and free memory. The libraries may well not support it. But the language does.

Your limitations are not really the compiler, but how the libraries are implemented, how much (or little) memory you have, both in terms of program space and RAM.

@Nick

StriDer99:
Did you try the code before posting? ...There's always something to learn.. :zipper_mouth_face:

Ok, ok.. The thing is that I tried that little piece of code and printed out just a bunch of squares. I retried it now and it's printing 42.
I am sorry, but I was disappointed 'cause I had the feeling you replied without reading my post with enough care.

I was just correcting a wrong statement... Since this is a learning forum, the point was that someone could learn a wrong thing.

Why are some libraries C, some C++? Is someone going backwards? Are C libraries old code? :open_mouth:
Well, as I said before, I am a C programmer, and don't know C++. I started the topic because I didn't know the existence of passing a parameter by reference to a function, and I got confused by declaration void breakTime(time_t t, tmElements_t &tm) in Time.h.
That is why I am comparing to C, to understand the differences. Also, I only worked on linux and windows, so I am new to microcontrollers in general, and of course to arduino....
I am just willing to learn more, learn it well, and to write good code, fully and deeply understanding what I am writing.

StriDer99:

You are like me. A very experienced Newbie who knows an awful lot about everything except the things you need to know right now.

You will get over it. ...with a little frustration.

Learn C++ if I can do it -- any one can...

Almost forgot. Welcome!

Thanks WillR, I will make it :wink:
So I probably will be an Arduino and C++ master, one day. Then I'll move on, to become again "a very experienced Newbie who knows an awful lot about everything except the things you need to know right now". That's what I love! (besides writing into forums)....
BTW: I am starting to love this forum!

StriDer99:
The thing is that I tried that little piece of code and printed out just a bunch of squares. I retried it now and it's printing 42.

Ah, if only the serial monitor auto-detected the baud rate. :wink:

StriDer99:
Why are some libraries C, some C++? Is someone going backwards? Are C libraries old code? :open_mouth:

Hmmm, why indeed? I suppose historical reasons. Some libraries, eg. the "old-style" string libraries (eg. strlen, strcpy) were always written in C, from the olden days. So it makes sense to keep existing, working, code.

There is no particular reason not to combine C and C++, bearing in mind some issues. One being name-mangling which is worked around by the way the C libraries are included. Another issue is doing a malloc on a C++ object which, generally speaking, will not work correctly, as malloc does not call constructors, whereas new does. Ditto for free compared to delete (vis-a-vis destructors). I notice that most of the examples I have seen have had C++ objects created on the stack, or statically, not by doing a new. There is a reason for that.

"Old" doesn't necessarily mean "bad". I'm old, for example (little joke there). So I wouldn't necessarily take a perfectly good, working library, and make it into C++ for no particular reason.

jraskell:

[quote author=Nick Gammon link=topic=56315.msg404308#msg404308 date=1300950860]
And it prints "42".

Where's my towel!
[/quote]

Ah, at least some of my jokes are appreciated. :wink:

oH MY ! :disappointed_relieved:
I missed a joke!
... I must read that book!

I used new, delete, and used them to allocate and free memory. The libraries may well not support it. But the language does.

Aha! I finally figured out why I can code on the Arduino more easily than "mainframe" C. No memory management!