Pointers
Indirection
Is the ability to reference something using a name, reference or container instead of the value itself.
The most common form of indirection is the act of manipulating a value through its memory address.
A pointer provides an indirect means of accessing the value of a particular data item a variable whose value is a memory address.
C provides a remarkably useful type of variable called a pointer, a variable that stores a memory address.
Its value is the address of another location in memory that can contain a value.
Pointers allow functions to modify data passed to them as variables.
Pass by reference passing arguments to function in a way they can be changed by function.
Can also be used to optimize program performance and speed by using less memory.
Declaring pointers
"numberPointer" now contains the address where variable "number" is stored.
Pointers must have the same variable type of the address values that contain the data for example char pointer, float pointer etc...
%p ->Represents the format specified for a pointer.
int *pointer = NULL; → is the equivalent of zero for a pointer, it doesn't point to any location in the memory.
Address of operator
The pointer simply points to the address of the variable and can act as an operator for using that variable.
De-referencing pointer to value
printf("%p", pnumber); → prints the pointer value printf("%d",*pnumber); → prints the value that its pointed to (number).
Displaying an address without a pointer
printf("number address: %p", &number);
or
printf("number address: %p", (void) &number); → (void) cast is to prevent possible warning from the compiler.
Example:
Pointers in expressions
int value = 999;
pnumber = &value;
*pnumber += 25; → The value of "value" variable is incremented by 25.
Example:
Pointers and const
We can use the const keyword when declaring a pointer to indicate that the value pointed to must not be changed.
The compiler will check for any statements that attempt to modify the value pointed to by pvalue and flag such statements as an error.
Pointers to constants
We can still modify value, we have only applied const to the pointer not the variable itself.
The value pointed to has changed but we didn't use the pointer to make the change. the pointer itself is not constant so we can still change what it points to:
We can create a constant pointer that points to a value that is also constant:
Now even though item variable is not defined as constant but the *const pointer makes it constant and we cant change the pointer or variable values.
Void pointers
The type name void means absence of any type a pointer of type void can contain the address of data item of any type.
Void is often used as a parameter type or return value type with functions that deal with data in a type-independent way.
Any kind of pointer can be passed around as a value of type void the void pointer can be doesn't know what type of object it is pointing to so it cant be de-referenced directly the void pointer must first be explicitly cast to another pointer type variable of type void.
When we want to access the integer value at the address stored in the void pointer, we must first cast the pointer to type int.
Example:
Pointers and arrays
An array is a collection of objects of the same type that you can refer to using a single name we can use a pointer to hold the address of different variables at different times(must be same type) arrays and pointers seem quit different but they are very closely related and can sometimes be used interchangeably.
The main reason for using pointers to arrays are ones of notional convenience and of program efficiency, pointers to arrays generally result in code that uses less memory and executes faster.
In pointers to arrays we point to each value of the array specifically and not the whole array at once.
Example:
If "ar" is an array the two expressions ar[i] and *(ar+i) are equivalent in meaning, both work if ar is the name of an array, both work if ar is a pointer variable using an expression such as ar++ only works if ar is a pointer variable.
Pointer arithmetic
To reference values[3] through the pvalues variable we can add 3 to pvalues and then apply the indirection operator.
This expression can be used to access the value contained in values[i].
For example to set vales[10] to 27:
The increment and decrement operators ++ and -- are particularly useful when dealing with pointers.
++pvalues; → sets pvalues pointing to the next integer in the values array (values[1]).
--pvalues; → sets pvalues pointing to the previous integer in the values array assuming that pvalues was not pointing to the beginning of the values array.
Example:
Example:
Example assigning and resolving array using pointers:
Pointers and strings
If text is an array of characters we can define a pointer to be used to point to elements in text.
Example:
Example:
Pass by reference
There are few ways to pass data to a function:
Pass by value.
Pass by reference.
Example pass by value:
Using pointers to pass data:
Passing data using copies of pointers
We can pass a pointer as an argument to a function and you can also have a function return a pointer as its result pass by reference copies the address of an argument into the formal parameter, the address is used to access the actual argument used in the call.
Means the changes made to the parameter affect the passed argument.
To pass a value by reference arguments pointers are passed to the functions just like an kind of value.
We need to declare the function parameters as pointer types.
Changes inside the function are reflected outside the function as well.
Unlike call by value where the changes do not reflect outside the function.
Example:
Returning a pointer from a function
Double pointers (pointer to a pointer)
As we are talked about de-referencing, there can be a reference for every variable and data type, including a pointer which is a reference to another variable itself.
A pointer which points to another pointer is called a double pointer and is works just like a normal pointer but it contains the address of a pointer instead of a variable.
Example:
Use cases
The biggest reason to use double pointers is when we need to change the value of the pointer passed to a function as the function argument.
Simulate pass by reference.
If you pass a single pointer in as argument you will be modifying local copies of the pointer not the original pointer in the calling scope.
With a pointer to a pointer you modify the original pointer.
We use a double pointer as an argument to a function when we want to preserve the memory-allocation or assignment even outside of the function.
Example:
In the example above the final printed value will still be 10 because the pointer that we used in the function parameter is locally assigned and like a regular variable this pointer has a local value.
When we define a pointer with the same name inside the main function we are giving it a new value so even after calling the foo function that value wont change so the output will be the value defined inside the main function.
Example:
This prints out 5.