why put "&" in front of a variable

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.

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.

See the "Arguments passed by value and by reference" section of:
http://www.cplusplus.com/doc/tutorial/functions/

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 :slight_smile: ) 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

Robin2:
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.

#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.

To make it clear (?)

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

My attempt to keep it simple and answer the OPs question

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.

1 Like

UKHeliBob:
My attempt to keep it simple and answer the OPs question

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

#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

#define ADDROF(a) (&(a))
#define VALAT(a) (*(a))

...R

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 !

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 [color=blue]%[/color] is MODULO, [color=blue]&[/color] is the bitwise AND Operator - when it's not the Address-of operator :slight_smile: which context will tell you about , [color=blue]&&[/color] is logical and etc... just part of the language to remember

Robin2:
Personally I would prefer

#define ADDROF(a) (&(a))

#define VALAT(a) (*(a))

well - there you go — nothing prevents you from doing so :slight_smile: (but if you want to be explicit then I would go for a full explanation _addressof (would reminds sizeof) and _valueat)

J-M-L:
well - there you go — nothing prevents you from doing so :slight_smile: (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 :slight_smile:

...R

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

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

:slight_smile: :slight_smile:

The line in the original post seems a little odd to me:

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:

// Either this:
receiver.write(text, sizeof(text));

// Or this:
receiver.write(&text[0], sizeof(text));

a pointer is the combination of the address and the type of data there, that's why you see different types of pointers:

char* myString; // a pointer to a char (array)
int* value;  // a pointer to an int16_t

gfvalvo:
...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:

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).

&text

so, like this:

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...

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:

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!

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

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

[sup][color=blue]512
512
hel
hel
HEllo world
[/color][/sup]

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

Your example does indeed work. But, I remember learning that the name of an array was a pointer to the first element in that array. In fact, all 3 methods work:

const char test[] = "this is a test";

void setup() 
{
  Serial.begin(115200);
  delay(2000);
  myFunct(test);
  myFunct(&test[0]);
  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.println(someArray);
}

Not sure if it's always been this way or compilers have gotten smarter since I learned Old School C back in college (30+ years ago).

EDIT: Looks like J-M-L beat me to it.

gfvalvo:
Your example does indeed work. But, I remember learning that the name of an array was a pointer to the first element in that array. In fact, all 3 methods work:

it is because of the casting of the parameter (char*) to the void* type... as I explained above in my edited post.

:wink:

And when you get bored having so much fun with pointers, you can up the fun level with data definitions like:

double (*(*pf)())[3][4];

Using the Right Left Rule, you can quickly see that pf is a pointer to a function that returns a pointer to an 3 by 4 array of doubles. Moral: You never get bored with C!

Robin2:
Personally I would prefer

#define ADDROF(a) (&(a))

#define VALAT(a) (*(a))



...R

:grinning:

it is funny (or very cleverly ironic) that you chose ADDROF, being that address is itself a homonym!!!

like any language with homonyms, context is very important. Once you learn really learn it your brain does the subconscious work of sorting out the context and allow the reader to understand it without having to think about decoding the meaning.

since C++ has a few homonyms (i.e. * and &) you'll struggle with the syntax until it finally clicks.

I think everyone who understands pointers knows how simple they are, but getting to the point where it clicks in... it is a bridge (guarded by a black knight?) that you must cross.

BulldogLowell:
:grinning:

it is funny (or very cleverly ironic) that you chose ADDROF, being that address is itself a homonym!!!

like any language with homonyms, context is very important. Once you learn really learn it your brain does the subconscious work of sorting out the context and allow the reader to understand it without having to think about decoding the meaning.

since C++ has a few homonyms (i.e. * and &) you'll struggle with the syntax until it finally clicks.

I think everyone who understands pointers knows how simple they are, but getting to the point where it clicks in... it is a bridge (guarded by a black knight?) that you must cross.

I think perhaps you need to look up the definition of "homonym". There is no definition by which '*' and '&' could possibly be considered homonyms...

Regards,
Ray L.