I'm just starting out with pointers, and I'm slightly confused. I know &
means the address of a variable and that *
can be used in front of a pointer variable to get the value of the object that is pointed to by the pointer. But things work differently when you're working with arrays, strings or when you're calling functions with a pointer copy of a variable. It's difficult to see a pattern of logic inside all of this.
When should I use &
and *
?
I was looking through all the wordy explanations so instead turned to a video from University of New South Wales for rescue.Here is the simple explanation: if we have a cell that has address
x
and value7
, the indirect way to ask for address of value7
is&7
and the indirect way to ask for value at addressx
is*x
.So(cell: x , value: 7) == (cell: &7 , value: *x)
.Another way to look into it:John
sits at7th seat
.The*7th seat
will point toJohn
and&John
will giveaddress
/location of the7th seat
. This simple explanation helped me and hope it will help others as well. Here is the link for the excellent video: click here.Here is another example:
Add-on: Always initialize pointer before using them.If not, the pointer will point to anything, which might result in crashing the program because the operating system will prevent you from accessing the memory it knows you don't own.But simply putting
p = &x;
, we are assigning the pointer a specific location.When you are declaring a pointer variable or function parameter, use the *:
NB: each declared variable needs its own *.
When you want to take the address of a value, use &. When you want to read or write the value in a pointer, use *.
Arrays are usually just treated like pointers. When you declare an array parameter in a function, you can just as easily declare it is a pointer (it means the same thing). When you pass an array to a function, you are actually passing a pointer to the first element.
Function pointers are the only things that don't quite follow the rules. You can take the address of a function without using &, and you can call a function pointer without using *.
There is a pattern when dealing with arrays and functions; it's just a little hard to see at first.
When dealing with arrays, it's useful to remember the following: when an array expression appears in most contexts, the type of the expression is implicitly converted from "N-element array of T" to "pointer to T", and its value is set to point to the first element in the array. The exceptions to this rule are when the array expression appears as an operand of either the
&
orsizeof
operators, or when it is a string literal being used as an initializer in a declaration.Thus, when you call a function with an array expression as an argument, the function will receive a pointer, not an array:
This is why you don't use the
&
operator for arguments corresponding to "%s" inscanf()
:Because of the implicit conversion,
scanf()
receives achar *
value that points to the beginning of thestr
array. This holds true for any function called with an array expression as an argument (just about any of thestr*
functions,*scanf
and*printf
functions, etc.).In practice, you will probably never call a function with an array expression using the
&
operator, as in:Such code is not very common; you have to know the size of the array in the function declaration, and the function only works with pointers to arrays of specific sizes (a pointer to a 10-element array of T is a different type than a pointer to a 11-element array of T).
When an array expression appears as an operand to the
&
operator, the type of the resulting expression is "pointer to N-element array of T", orT (*)[N]
, which is different from an array of pointers (T *[N]
) and a pointer to the base type (T *
).When dealing with functions and pointers, the rule to remember is: if you want to change the value of an argument and have it reflected in the calling code, you must pass a pointer to the thing you want to modify. Again, arrays throw a bit of a monkey wrench into the works, but we'll deal with the normal cases first.
Remember that C passes all function arguments by value; the formal parameter receives a copy of the value in the actual parameter, and any changes to the formal parameter are not reflected in the actual parameter. The common example is a swap function:
You'll get the following output:
The formal parameters
x
andy
are distinct objects froma
andb
, so changes tox
andy
are not reflected ina
andb
. Since we want to modify the values ofa
andb
, we must pass pointers to them to the swap function:Now your output will be
Note that, in the swap function, we don't change the values of
x
andy
, but the values of whatx
andy
point to. Writing to*x
is different from writing tox
; we're not updating the value inx
itself, we get a location fromx
and update the value in that location.This is equally true if we want to modify a pointer value; if we write
then we're modifying the value of the input parameter
stream
, not whatstream
points to, so changingstream
has no effect on the value ofin
; in order for this to work, we must pass in a pointer to the pointer:Again, arrays throw a bit of a monkey wrench into the works. When you pass an array expression to a function, what the function receives is a pointer. Because of how array subscripting is defined, you can use a subscript operator on a pointer the same way you can use it on an array:
Note that array objects may not be assigned; i.e., you can't do something like
so you want to be careful when you're dealing with pointers to arrays; something like
won't work.