Go Down

Topic: why put "&" in front of a variable (Read 12461 times) previous topic - next topic

spd1989

I have been working with the nrf24l01, and one of the lines of code is:

        receiver.write(&text, sizeof(text));



Everything works correctly, I'm just curious as to why there is an "&" in front of "text".


I have seen this in several programs, and I still haven't been able to find an explanation as to why this is done...because when I search, I only find stuff about "&&" which is something completely different.

Power_Broker

I suggest you look it up here. The tutorial explains it quite well.

Basically, the & symbol returns the address (in physical memory) of the proceeding variable.
"The desire that guides me in all I do is the desire to harness the forces of nature to the service of mankind."
   - Nikola Tesla

pert


Robin2

#3
Jun 18, 2017, 09:21 am Last Edit: Jun 18, 2017, 10:31 am by Robin2
I have looked at both of those links and IMHO neither of them provides a simple answer to the OP's question.

The concept of pointers is very simple but the folks who invented C went out of their way to obfuscate things by using * and & rather than some more meaningful 3-letter acronym that would not need explaining.

It is several weeks since I did any code with pointers and to be honest I have forgotten the details (again). IIRC the & signifies that you want to use the value that is at the address in the variable. So &text is used when "text" has an address where data is stored and you want to use the data rather than use the address in your calculations. So &text is used when you want to pass the address of the variable where data is stored rather than the value that is at that location.

Think of it like asking the postman to deliver a package. One action is to tell him to deliver it to house number 23. And a very different action (probably illegal in the real world :) ) is to get him to show you the package that is addressed to house number 23.

No doubt if I have got mixed up between the roles of * and & someone will be quick to point it out. (I did, and I hope I have corrected it.)

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

PaulMurrayCbr

The concept of pointers is very simple but the folks who invented C went out of their way to obfuscate things by using * and & rather than some more meaningful 3-letter acronym that would not need explaining.
Code: [Select]

#define REF(a) (&(a))
#define DEREF(a) (*(a))

receiver.write(REF(text), sizeof(text));


Simple! Not. You cannot make anything "simple" whose underlying concepts are somewhat difficult - and pointers are difficult, otherwise people wouldn't have such trouble with them - by providing cute syntax. That's what COBOL "noise words" are. They don't help.
http://paulmurraycbr.github.io/ArduinoTheOOWay.html

J-M-L

#5
Jun 18, 2017, 09:39 am Last Edit: Jun 18, 2017, 10:53 am by J-M-L
To make it clear (?)

Code: [Select]
char myCharacter = 'x'; // allocate memory for one byte, myCharacter represents the content in memory, 'x'
char * myCharacterAddress = &myCharacter; // the memory address where 'x' is stored, we call that a pointer
char myContent1 = *myCharacterAddress; // this is 'x', * goes get the content of the memory address
char myContent2 = myCharacter; // same thing, will get 'x'
Of course more useful with arrays than with just une character and this is used in functions to say I've plenty of data at that's space in memory want you to use, rather than duplicating what is in memory when calling the function

May be pictures explains better:

with an integer on a UNO (2 bytes):



or with a char array (null terminated to represent strings in C)


hope this helps
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

UKHeliBob

My attempt to keep it simple and answer the OPs question
Code: [Select]
receiver.write(&text, sizeof(text));
Putting & in front of the name of the variable passes the memory address of the variable to the function rather than the value of the variable.

As to why, well, by passing the address it gives the function the ability to modify the value at the address so that the value is then available to other parts of the program.

This is particularly useful when needing to share the values held in an array, as passing the memory address allows any/all of the elements to be accessed and modified, which is where passing the size of the array comes in.  Knowing the start address of the array and how many bytes the array uses means that each of the array elements can be accessed and changed.

NOTE :  determining how many array elements there are by directly using the size of the array only works when using variable types that use one byte, such as byte and char, but there are ways to do it with larger data types.
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Robin2

#7
Jun 18, 2017, 10:28 am Last Edit: Jun 18, 2017, 10:35 am by Robin2
My attempt to keep it simple and answer the OPs question
Code: [Select]
receiver.write(&text, sizeof(text));
Putting & in front of the name of the variable passes the memory address of the variable to the function rather than the value of the variable.
Which means I got it back to front in Reply #3 (which does not surprise me). I will try to correct it.


From Reply #4
Quote
Code: [Select]
#define REF(a) (&(a))
#define DEREF(a) (*(a))

receiver.write(REF(text), sizeof(text));


Simple! Not.
That looks reasonably simple  - why do you say it is not?

Personally I would prefer
Code: [Select]
#define ADDROF(a) (&(a))
#define VALAT(a) (*(a))



...R
Two or three hours spent thinking and reading documentation solves most programming problems.

UKHeliBob

Quote
Which means I got it back to front in Reply #3 (which does not surprise me). I will try to correct it.
I only hope that I have got it right !
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

J-M-L

#9
Jun 18, 2017, 11:11 am Last Edit: Jun 18, 2017, 11:13 am by J-M-L
Some pretty cryptic notations got promoted to plain english, you can use and instead of && for example but pointers never got addressed - which is totally fine by me - I put that in the same category as remembering % is MODULO, & is the bitwise AND Operator - when it's not the Address-of operator :) which context will tell you about , && is logical and etc... just part of the language to remember 

Personally I would prefer
Code: [Select]
#define ADDROF(a) (&(a))
#define VALAT(a) (*(a))

well - there you go -- nothing prevents you from doing so :) (but if you want to be explicit then I would go for a full explanation _addressof (would reminds sizeof) and _valueat)
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

Robin2

#10
Jun 18, 2017, 11:17 am Last Edit: Jun 18, 2017, 11:26 am by Robin2
well - there you go -- nothing prevents you from doing so :) (but if you want to be explicit then I would go for a full explanation _addressof (would reminds sizeof) and _valueat)
Very sensible.

But the problem is that none of these ideas does anything for code that has already been written using * and & because you cannot simply do a search-and-replace.

And it's no good reminding myself that & (and) starts with 'a' and so does address. Because * (asterisk) also starts with 'a' and in any case & is really "et". Phoning Home would be just as useful.

To make matters even more confusing (and going back to the original question) if the vraibale being used with receiver.write(&text, sizeof(text)); is an array the use of the & is optional because C treats an array as an address automatically.

Then, of course, the $64k question - why would a receiver be writing :)

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

J-M-L

#11
Jun 18, 2017, 11:23 am Last Edit: Jun 18, 2017, 12:22 pm by J-M-L
true ! hence probably best to go with it and just remember the language definition... I got used to it over time and even if I don't use that much it's like ridding a bicycle once you got it it sticks but agree it's cryptic


Then, of course, the $64k question - why would a receiver be writing :)
:) :)
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

gfvalvo

#12
Jun 18, 2017, 02:28 pm Last Edit: Jun 18, 2017, 02:34 pm by gfvalvo
The line in the original post seems a little odd to me:
Code: [Select]
receiver.write(&text, sizeof(text));
We don't have the complete code, but from the context I'd guess that 'text' is an array of 'char'. If so, 'text' is already a pointer. I would think the call should be:
Code: [Select]
// Either this:
receiver.write(text, sizeof(text));

// Or this:
receiver.write(&text[0], sizeof(text));
No technical questions via PM. They will be ignored. Post your questions in the forum so that all may learn.

BulldogLowell

#13
Jun 18, 2017, 03:06 pm Last Edit: Jun 19, 2017, 02:46 pm by BulldogLowell
a pointer is the combination of the address and the type of data there, that's why you see different types of pointers:

Code: [Select]
char* myString; // a pointer to a char (array)
int* value;  // a pointer to an int16_t


...I'd guess that 'text' is an array of 'char'. If so, 'text' is already a pointer. I would think the call should be:
no.

the source is simple:
Code: [Select]

bool RF24::write(const void * buf, uint8_t len)


hmmm... what's that, a void pointer?

yes, in this case they are using a void or "typeless" pointer... so, to pass the char array  (it seems in this case) you pass only the address of the pointer which essentially strips the type off of the pointer (all you need for a void pointer).

Code: [Select]
&text

so, like this:

Code: [Select]
const char test[] = "this is a test";

void setup()
{
  Serial.begin(9600);
  myFunct(&test);

}

void loop()
{
}

void myFunct(const void* vdPtr)
{
  char* someArray;  // creates a pointer to some char array
  someArray = (char*)vdPtr; // cast the void pointer to a char* and assign it to someArray
  Serial.print(someArray);
}


Why do this?  you can then write() arrays of different types...

Code: [Select]

const char test[] = "this is a test";
const byte data[] = {0xff, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0x00};

void setup()
{
  Serial.begin(9600);
  myFunct(&test, sizeof(test));
  myFunct(&data, sizeof(data));

}

void loop()
{
}

void myFunct(const void* vdPtr, size_t size)
{
  char* someArray;  // creates a pointer to some char array
  someArray = (char*)vdPtr; //cast the void pointer to a char* and assign it to someArray
  Serial.write(someArray, size);
  Serial.write('\n');
}


powerful stuff...

EDITED:

Quote
Everything works correctly, I'm just curious as to why there is an "&" in front of "text".
what happens if you don't include the & operator?  the parameter (pointer to char or pointer to byte) will be cast to a void pointer!

why use it at all?  good programming technique!!  displays that there is more behind what's going to happen... it begs any casual programmer to go look at the function!


J-M-L

#14
Jun 18, 2017, 03:17 pm Last Edit: Jun 18, 2017, 03:41 pm by J-M-L
agree it feels fishy but the compiler (depending on your warning or cast settings) will give the address of the array with the name of the array or &array

for example
Code: [Select]
char text[] = "hello world";
char * textPtr1 = (char *) &text;
char * textPtr2 = text;

void setup() {
  Serial.begin(115200);
  Serial.println((uint16_t) textPtr1);
  Serial.println((uint16_t) textPtr2);
  Serial.print(*textPtr1);  Serial.print(*(textPtr1+1));Serial.println(*(textPtr1+2));
  Serial.print(*textPtr2);  Serial.print(*(textPtr2+1));Serial.println(*(textPtr2+2));
  *textPtr1 = 'H';
  *(textPtr2+1) = 'E'; 
  Serial.println(text);
}

void loop() {}


will print out

512
512
hel
hel
HEllo world

so we can see the buffer at been allocated at position 512 in RAM and both pointers are pointing towards that location and if we read data from both it works or modify data from both it works too

Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

Go Up