34

A C++ question,

I know

int* foo(void)

foo will return a pointer to int type

how about

int &foo(void)

what does it return?

Thank a lot!

sbi
  • 219,715
  • 46
  • 258
  • 445
Alfred Zhong
  • 341
  • 1
  • 4
  • 3

8 Answers8

56

It returns a reference to an int. References are similar to pointers but with some important distinctions. I'd recommend you read up on the differences between pointers, references, objects and primitive data types.

"Effective C++" and "More Effective C++" (both by Scott Meyers) have some good descriptions of the differences and when to use pointers vs references.

EDIT: There are a number of answers saying things along the lines of "references are just syntactic sugar for easier handling of pointers". They most certainly are not.

Consider the following code:

int a = 3;
int b = 4;
int* pointerToA = &a;
int* pointerToB = &b;
int* p = pointerToA;
p = pointerToB;
printf("%d %d %d\n", a, b, *p); // Prints 3 4 4
int& referenceToA = a;
int& referenceToB = b;
int& r = referenceToA;
r = referenceToB;
printf("%d %d %d\n", a, b, r); // Prints 4 4 4

The line p = pointerToB changes the value of p, i.e. it now points to a different piece of memory.

r = referenceToB does something completely different: it assigns the value of b to where the value of a used to be. It does not change r at all. r is still a reference to the same piece of memory.

The difference is subtle but very important.

If you still think that references are just syntactic sugar for pointer handling then please read Scott Meyers' books. He can explain the difference much better than I can.

Cameron Skinner
  • 51,692
  • 2
  • 65
  • 86
  • 1
    +1 for Scott Meyers books. Must-haves for anyone who wants to have a good understanding of C++. – Matthieu Jan 07 '11 at 19:18
  • 1
    Yes, they are both excellent books. Taught me everything I know! – Cameron Skinner Jan 07 '11 at 19:19
  • Reference variables are thus an alternate syntax for *const* pointers. – Bento Sep 13 '16 at 03:10
  • @Bento: No, that's not correct. You cannot do this: ```int* const p = &a; p = &b;```, but you can do this: ```int& r = a; r = b;```. References are not pointers, const or not. – Cameron Skinner Sep 14 '16 at 00:54
  • Consider the following code: ```int& r = a; r = b;```. If your assertion were true, then you could replace the ```int&``` with ```int* const``` and the code should still compile. Try it and see - you'll find that ```int* const``` is not the same thing as ```int&```. – Cameron Skinner Sep 14 '16 at 01:00
  • @Cameron: I did not simply mean `int&` <=> `int* const`, but I meant that _and_ the other opportune substitutions — i.e., replacing `r = b` with dereferencing `*p = b`. In this sense, the two syntaxes do the same work. – Bento Sep 14 '16 at 05:44
  • They look similar, but you need to remember that they have different behavior. For example, a reference can never be null. It's a bad idea to think that they are just different ways of describing a single thing - you will wind up with subtle and confusing bugs. Understanding the differences and using the two constructs appropriately will help you to write more robust code. I encourage you to read Scott Meyers' books for an in-depth discussion of the differences between references and pointers. That will serve you better than an extended comment on StackOverflow :) – Cameron Skinner Sep 14 '16 at 07:04
5

Be careful here... you're walking the C/C++ line. There's a quite clear distinction but it doesn't always appear that way:

C++: this often means a reference. For example, consider:

void func(int &x)
{
   x = 4;
}

void callfunc()
{
    int x = 7;
    func(x);
}

As such, C++ can pass by value or pass by reference.

C however has no such pass by reference functionality. & means "addressof" and is a way to formulate a pointer from a variable. However, consider this:

void func(int* x)
{
   *x = 4;
}

void callfunc()
{
    int x = 7;
    func(&x);
}

Deceptively similar, yet fundamentally different. What you are doing in C is passing a copy of the pointer. Now these things still point to the same area of memory, so the effect is like a pass by reference in terms of the pointed-to memory, but it is not a reference being passed in. It is a reference to a point in memory.

Try this (Compile as C):

#include <stdio.h>

void addptr(int* x)
{
    printf("Add-ptr scope 1:\n");
    printf("Addr: %p\n", x);
    printf("Pointed-to-memory: %d\n", *x);
    *x = *x + 7;
    x++;
    printf("Add-ptr scope 2:\n");
    printf("Addr: %p\n", x);
    printf("Pointed-to-memory: %d\n", *x);
}

int main(int argc, char** argv)
{
    int a = 7;
    int *y = &a;
    printf("Main-Scope 2:\n");
    printf("Addr: %p\n", y);
    printf("Pointed-to-memory: %d\n", *y);
    addptr(y);
    printf("Main-Scope 2:\n");
    printf("Addr: %p\n", y);
    printf("Pointed-to-memory: %d\n", *y);
    return 0;

}

If C had pass by reference, the incoming pointer address, when changed by addptr should be reflected in main, but it isn't. Pointers are still values.

So, C does not have any pass by reference mechanism. In C++, this exists, and that is what & means in function arguments etc.

Edit: You might be wondering why I can't do this demonstration in C++ easily. It's because I can't change the address of the reference. At all. From this quite good guide to references:

How can you reseat a reference to make it refer to a different object?

No way.

You can't separate the reference from the referent.

Unlike a pointer, once a reference is bound to an object, it can not be "reseated" to another object. The reference itself isn't an object (it has no identity; taking the address of a reference gives you the address of the referent; remember: the reference is its referent).

In that sense, a reference is similar to a const pointer such as int* const p (as opposed to a pointer to const such as int const* p). But please don't confuse references with pointers; they're very different from the programmer's standpoint.

By request, on returning references:

#include <iostream>

using namespace std;

int& function(int f)
{
   f=f+3;
   return f;
}

int main(int argc, char** argv)
{
    int x = 7;
    int y;
    y = function(x);
    cout << "Input: " << x << endl;
    cout << "Output:" << y << endl;
    return 0;
}

Any good compiler ought to give you this warning message in some form:

exp.cpp:7:11: warning: reference to stack memory associated with local variable 'f' returned

What does this mean? Well, we know function arguments are pushed onto the stack (note: not actually on x64, they go into registers then the stack, but they are on the stack literally on x86) and what this warning is saying is that creating a reference to such an object is not a good idea, because it's not guaranteed to be left in place. The fact it is is just luck.

So what gives? Try this modified version:

#include <iostream>

using namespace std;

int& function(int& f)
{
    f=f+3;
    return f;
}

int main(int argc, char** argv)
{
    int x = 7;
    int y;
    y = function(x);
    cout << "Input: " << x << endl;
    cout << "Output:" << y << endl;
    return 0;
}

Run this, and you'll see both values get updated. What? Well they both refer to the same thing and that thing is being edited.

Jay Elston
  • 1,978
  • 1
  • 19
  • 38
  • 1
    Thanks a lot! I know in C &foo, and if foo is an int, it will be foo's address, and can be pass to int* type. What I am confused is when it is used in function declaration, int &foo(...), what doesn't it mean? – Alfred Zhong Jan 07 '11 at 19:44
  • "What you are doing in C is passing a copy of the pointer." No you aren't - you're passing the *value* of the *address* of the local variable `x` to `func` as a *pointer* argument. At that stage there are no other pointers so you can't be copying one. In the C++ example you are passing a the variable `x` to a function that takes a *reference* argument, so what you get is a reference to `x`. The implementation of these is (probably) the same: the address of `x` gets pushed onto the stack. IOW C *does* does allow you to use reference semantics, but it does not provide syntax to support them. – dajames Jan 07 '11 at 20:13
  • Yes, you are passing a *copy* of the pointer's value - a *copy of the pointer*. A pointer is a memory address in and of itself (therefore a "variable") containing another memory address. Attach `gdb` to a process and you'll be able to see this. Therefore the act of copying it is to assign a new memory space and put the value in. This is what pass by value means. –  Jan 07 '11 at 20:51
  • Pass by reference is explicitly a language feature. Language only. The end result is very similar, but it is important to highlight differences in the way languages work. –  Jan 07 '11 at 20:58
1

It returns a reference to an int variable.

trojanfoe
  • 120,358
  • 21
  • 212
  • 242
1

This question isn't C/C++ at all, as C does not have references, only pointers. An int& is a reference to an int. Also, you don't need void, it can just be int& foo();

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • This is what the document says, Texas instrument's TMS320C28x C/C++ compiler intrinsics, http://focus.ti.com/lit/ug/spru514c/spru514c.pdf, page 122, int&__byte(int, unsigned int), I guess it is different from PC – Alfred Zhong Jan 07 '11 at 19:49
  • @Alfred: No, not really. The C and C++ languages do not have special embedded versions. The manual is wrong, and that's pretty much it. – Puppy Jan 07 '11 at 19:51
  • @Alfred Zhong. No the documentation says the same as everybody else here. – Martin York Jan 07 '11 at 19:56
1

From Alfred's comments

This is what the document says, Texas instrument's TMS320C28x C/C++ compiler intrinsics, page 122, int&__byte(int, unsigned int), I guess it is different from PC – Alfred Zhong

From the manual:

int &__byte(int *array, unsigned int byte_index);

MOVB array[byte_index].LSB, src

The lowest adressable unit in C28x is 16 bits. Therefore, normally you cannot access 8-bit MOVB dst, array[byte_index]. LSB entities off a memory location. This intrinsic helps access an 8-bit quantity off a memory location, and can be invoked as follows:

__byte(array,5) = 10;
b = __byte(array,20);

This just means that the function returns a reference to an integer that acts like an 8 bit quantity. Because the value is a reference modifying will modify the object at the destination (just like the MOVB) instruction, while assigning to b will copy (just like MOVB) to the destination.

Martin York
  • 257,169
  • 86
  • 333
  • 562
  • Thanks Martin, I am confused because I did exactly as the manual says, __byte(array,5)=10, and the compiler keep complaining "error: expression must be a modifiable lvalue" – Alfred Zhong Jan 07 '11 at 20:09
0

just playing with variables to show you the meaning

int i = 5;
int * pI = &i;
int & referenceToI = * pI;
referenceToI = 4; // now i == 4

EDIT: References are just a syntactic sugar for easier pointers handling. at the assembly level, the code generated by the compiler returns to a you an address-pointer

Stephane Rolland
  • 38,876
  • 35
  • 121
  • 169
0

https://isocpp.org/wiki/faq/references

This page says it succinctly! A reference is an alias. It IS the object, just by another name. The previous name is still valid. The reference is not a stand-alone object. It IS the object by a different name. You cannot operate on the reference because it is not a thing unto itself. It is just an alias of the original object.

It is that simple. Now you can think of it easily rather than the round and round in the above posts.

0

int& is a reference. To be more precise, a reference variable is simply an alternative name of an existing variable.

Example: Consider below code

main(){
    int x = 4;
    int& ref_of_x = x;
    // Now, modifying x modifies ref_of_x too and vice-versa
    x = 5;
    cout<<ref_of_x; //This prints 5
    
    ref_of_x = 15;
    cout<<x;  // This prints 15
    }