1

Here is the way I understand * and & symbols in C and C++.

In C, * serves two purposes. First it can be used to declare a pointer variable like so int* pointerVariable

It can however be used as a dereference operator like so *pointerVariable which returns value saved at that address, it understands how to interpret bytes at that address based on what data type we have declared that pointer is pointing to. In our case int* therefore it reads bytes saved at that address and returns back whole number.

We also have address-of operator in C like so &someVariable which returns address of bytes saved underneath someVariable name.

However in C++ (not in C), we also get a possibility to use & in declaration of reference like so int& someReference. This will turn variable someReference into a reference, which means that whatever value we pass into that variable, it will automatically get address of the value we are passing into it and it will hold it.

Do I get this correctly?

anastaciu
  • 23,467
  • 7
  • 28
  • 53
ShoeMaker
  • 149
  • 1
  • 2
  • 9
  • 1
    Does this answer your question? [What exactly is the purpose of the (asterisk) in pointers?](https://stackoverflow.com/questions/36962658/what-exactly-is-the-purpose-of-the-asterisk-in-pointers) – rsjaffe Aug 09 '20 at 20:13
  • It doesn’t deal with references and address of – ShoeMaker Aug 09 '20 at 20:15
  • 2
    that's because you have multiple questions here. Stackoverflow does not handle multiple questions in a single post. – rsjaffe Aug 09 '20 at 20:16
  • 1
    Yes, your understanding seems to be correct. – HolyBlackCat Aug 09 '20 at 20:17
  • 1
    @rsjaffe: Multiple related questions are reasonable to ask about together, particularly where the subjects overlap and need to be compared and contrasted. – Eric Postpischil Aug 09 '20 at 20:22
  • 1
    Your frame of mind for references is counter-productive in my opinion. A reference is just a name for an existing object. It is not an address in the abstract sense that a C++ program deals with. Much confusion (and bugs) happens when trying to think about references as syntactic sugar for pointers. – StoryTeller - Unslander Monica Aug 09 '20 at 20:23
  • Exactly. I think things I am asking overlap so that’s the reason why I am asking about this in one question – ShoeMaker Aug 09 '20 at 20:24
  • 1
    The appearance of the asterisk in declarations and in expressions is more two sides of the same coin than two different purposes. In an expression, `*p` refers to the object that `p` points to. In a declaration such as `int *p`, it means “When `*p` is used in an expression, it will be an `int`,” from which we infer that `p` must be a pointer to an `int`. – Eric Postpischil Aug 09 '20 at 20:25
  • 1
    "_`*pointerVariable` which returns value saved at that address_" - I would say that it returns a reference to the object pointed at by `pointerVariable`. – Ted Lyngmo Aug 09 '20 at 20:27
  • If you want reference to something, you need to use “address-of” operator &. * serves dereferencing ie returning value saved at that address – ShoeMaker Aug 09 '20 at 20:30
  • @ShoeMaker I'm not sure if you're asking or telling? The address-of operator returns a pointer to the object which is not what you want to use if you want a reference to something. – Ted Lyngmo Aug 09 '20 at 20:35
  • Address-of returns a reference (address) that can be saved in a pointer (variable which holds addresses) – ShoeMaker Aug 09 '20 at 20:41
  • 1
    Ok, sure, and `*pointerVariable` returns a reference to the original object. – Ted Lyngmo Aug 09 '20 at 20:45
  • @TedLyngmo `*pointerVariable` is an lvalue, not a reference – M.M Aug 09 '20 at 20:52
  • *pointerVariable dereferences. Meaning it returns a value saved at that reference/address. – ShoeMaker Aug 09 '20 at 20:53
  • @M.M and ShoeMaker: If it returned by value it'd be hard to do this: https://godbolt.org/z/9T3WE1 – Ted Lyngmo Aug 09 '20 at 20:54
  • @ShoeMaker `*pointerVariable` doesn't return the value saved at the address . It's an lvalue expression that designates a memory location. The value is only retrieved if you apply an operator or use a context that retrieves the value . Counterexample: `*pointerVariable = 5;` – M.M Aug 09 '20 at 21:01
  • @TedLyngmo I said "is an lvalue", not "returned by value". Expressions don't return – M.M Aug 09 '20 at 21:02
  • Actually, there is a third purpose for `*` in C. The binary operator `*` is used for multiplication. – eerorika Aug 09 '20 at 21:03
  • @M.M Fair enough. Sloppy reading on my part. – Ted Lyngmo Aug 09 '20 at 21:04

4 Answers4

3

Do I get this correctly?

Yes, but it is better to think about pointers and references in terms of what you want to do.

References are very useful for all those cases where you need to refer to some object without copying it. References are simple: they are always valid and there is no change in syntax when you use the object.

Pointers are for the rest of cases. Pointers allow you to work with addresses (pointer arithmetic), require explicit syntax to refer to the object behind them (*, &, -> operators), are nullable (NULL, nullptr), can be modified, etc.

In summary, references are simpler and easier to reason about. Use pointers when a reference does not cut it.

Acorn
  • 24,970
  • 5
  • 40
  • 69
1
  1. General Syntax for defining a pointer:
    data-type * pointer-name = &variable-name
    The data-type of the pointer must be the same as that of the variable to which it is pointing.
    void type pointer can handle all data-types.
  2. General Syntax for defining a reference variable:
    data-type & reference-name = variable-name
    The data-type of the reference variable must be the same as that of the variable of which it is an alias.

Let's look at each one of them, for the purpose of explanation, I will go with a simple Swap Program both in C and C++.


Swapping two variables by the pass by reference in C

#include <stdio.h>
void swap(int *,int *); //Function prototype
int main()
{
    int a = 10;
    int b = 20;
    printf("Before Swap: a=%d, b=%d\n",a,b);
    swap(&a,&b); //Value of a,b are passed by reference
    printf("After Swap: a=%d, b=%d\n",a,b);
    return 0;
}

void swap(int *ptra,int *ptrb)
{
    int temp = *ptra;
    *ptra = *ptrb;
    *ptrb = temp;
}
  • In the code above we have declared and initialized variable a and b to 10 and 20 respectively.
  • We then pass the address of a and b to swap function by using the addressof (&) operator. This operator gives the address of the variable.
  • These passed arguments are assigned to the respective formal parameters which in this case are int pointers ptra and ptrb.
  • To swap the variables, we first need to temporarily store the value of one of the variables. For this, we stored value pointed by the pointer ptra to a variable temp. This was done by first dereferencing the pointer by using dereference (*) operator and then assigning it to temp. dereference (*) operator is used to access the value stored in the memory location pointed to by a pointer.
  • Once, the value of pointed by ptra is saved, we can then assign it a new value, which in this case, we assigned it the value of variable b(again with the help of dereference (*) operator). And the ptrb was assigned the value saved in temp(original value of a). Therefore, swapping the value of a and b, by altering the memory location of those variables.

Note: We can use dereference (*) operator and the addressof (&) operator together like this, *&a, they nullify each other resulting in just a


We can write a similar program in C++ by using pointers to swap two numbers as well but the language supports another type variable known as the reference variable. It provides an alias (alternative name) for a previously defined variable.

Swapping two variables by the call by reference in C++

#include <iostream>
using namespace std;
void swap(int &,int &); //Function prototype
int main()
{
    int a = 10;
    int b = 20;
    cout << "Before Swap: a= " << a << " b= " << b << endl;
    swap(a,b);
    cout << "After Swap: a= " << a << " b= " << b << endl;
    return 0;
}

void swap(int &refa,int &refb)
{
    int temp = refa;
    refa = refb;
    refb = temp;
}
  • In the code above when we passed the variables a and b to the function swap, what happened is the variable a and b got their respective reference variables refa and refb inside the swap. It's like giving a variable another alias name.
  • Now, we can directly swap the variables without the dereferencing (*) operator using the reference variables.
  • Rest logic remains the same.
Sourabh Choure
  • 723
  • 4
  • 15
0

So before we get into the differences between pointers and references, I feel like we need to talk a little bit about declaration syntax, partly to explain why pointer and reference declarations are written that way and partly because the way many C++ programmers write pointer and reference declarations misrepresent that syntax (get comfortable, this is going to take a while).


In both C and C++, declarations are composed of a sequence of declaration specifiers followed by a sequence of declarators1. In a declaration like

static unsigned long int a[10], *p, f(void);

the declaration specifiers are static unsigned long int and the declarators are a[10], *p, and f(void).

Array-ness, pointer-ness, function-ness, and in C++ reference-ness are all specified as part of the declarator, not the declaration specifiers. This means when you write something like

int* p;

it’s parsed as

int (*p);

Since the unary * operator is a unique token, the compiler doesn't need whitespace to distinguish it from the int type specifier or the p identifier. You can write it as int *p;, int* p;, int * p;, or even int*p;

It also means that in a declaration like

int* p, q;

only p is declared as a pointer - q is a regular int.

The idea is that the declaration of a variable closely matches its use in the code ("declaration mimics use"). If you have a pointer to int named p and you want to access the pointed-to value, you use the * operator to dereference it:

printf( "%d\n", *p );

The expression *p has type int, so the declaration of p is written

int *p;

This tells us that the variable p has type "pointer to int" because the combination of p and the unary operator * give us an expression of type int. Most C programmers will write the pointer declaration as shown above, with the * visibly grouped with p.

Now, Bjarne and the couple of generations of C++ programmers who followed thought it was more important to emphasize the pointer-ness of p rather than the int-ness of *p, so they introduced the

int* p;

convention. However, this convention falls down for anything but a simple pointer (or pointer to pointer). It doesn't work for pointers to arrays:

int (*a)[N];

or pointers to functions

int (*f)(void);

or arrays of pointers to functions

int (*p[N])(void);

etc. Declaring an array of pointers as

int* a[N];

just indicates confused thinking. Since [] and () are postfix, you cannot associate the array-ness or function-ness with the declaration specifiers by writing

int[N] a;
int(void) f;

like you can with the unary * operator, but the unary * operator is bound to the declarator in exactly the same way as the [] and () operators are.2

C++ references break the rule about "declaration mimics use" hard. In a non-declaration statement, an expression &x always yields a pointer type. If x has type int, &x has type int *. So & has a completely different meaning in a declaration than in an expression.


So that's syntax, let's talk about pointers vs. references.

A pointer is just an address value (although with additional type information). You can do (some) arithmetic on pointers, you can initialize them to arbitrary values (or NULL), you can apply the [] subscript operator to them as though they were an array (indeed, the array subscript operation is defined in terms of pointer operations). A pointer is not required to be valid (that is, contain the address of an object during that object's lifetime) when it's first created.

A reference is another name for an object or function, not just that object's or function's address (this is why you don't use the * operator when working with references). You can't do pointer arithmetic on references, you can't assign arbitrary values to a reference, etc. When instantiated, a reference must refer to a valid object or function. How exactly references are represented internally isn't specified.


  1. This is the C terminology - the C++ terminology is a little different.
  2. In case it isn't clear by now I consider the T* p; idiom to be poor practice and responsible for no small amount of confusion about pointer declaration syntax; however, since that's how the C++ community has decided to do things, that's how I write my C++ code. I don't like it and it makes me itch, but it's not worth the heartburn to argue over it or to have inconsistently formatted code.
John Bode
  • 119,563
  • 19
  • 122
  • 198
0

Simple answer:

Reference variables are an alias to the data passed to them, another label.

int var = 0;
int& refVar = var;

In practical terms, var and refVar are the same object.

Its worth noting that references to heap pointer data cannot deallocate (delete) the data, as its an alias of the data;

int* var = new int{0};
int& refVar = *var;
delete refVar // error

and references to the pointer itself can deallocate (delete) the data, as its an alias of the pointer.

int* var = new int{0};
int*& refVar = var;
delete refVar // good
M.Kerr
  • 58
  • 5