Pointer to object#
Object#
For example:
int number = 42;
char name[] = "Partha";
numberis the identifier of the object42.42is stored in an data storage area of 4 bytes.nameis the identifier of the object"Partha". This object consists of 7 characters.
We used pointers before#
Remember the following diagram from section Arguments and return value in functions:
flowchart LR
x[argument/s]:::dashed <--> B[function]
B -- return value --> y:::hidden
classDef hidden display: none;
classDef dashed stroke-dasharray:5;
Do you remember
what the arrow tips (directions) mean?
an example where a function writes to its arguments?
Meaning#
Fig. 21 A pointer variable a which has the value 1008. 1008 is an address. If we dereference a, we get the value of the variable b.#
Source CC-BY-SA 3.0 Unported by User:Sven
Example:
#include <stdio.h>
int main() {
int b = 42;
int *a = &b;
printf(" b: %d\n", b);
printf("&b: %p\n", &b);
puts("");
printf(" a: %p\n", a);
printf("*a: %d\n", *a);
printf("&a: %p\n", &a);
}
b: 42
&b: 0x7ffccb71570c
a: 0x7ffccb71570c
*a: 42
&a: 0x7ffccb715700
Declaration#
int *a; // Pointer to an `int`
char *c; // Pointer to a `char`
int **d; // Pointer to a pointer to an `int`
float *e = nullptr; // Initialization with zero
// Better than `0`, because `nullptr` identifier shows intent
Usage#
Operator |
Meaning |
Example |
|---|---|---|
|
dereference |
|
|
address of |
|
Activity 42 (Meaning of pointer operators)
Which are correct for the code above?
a == 42*a == 42&a == 42&*b == 42*&b == 42
Activity 43 (Declaring and using a pointer)
Code the following:
Declare and initialize an
unsignednumber calledn.Declare and initialize a pointer to
ncalledp1.Declare and initialize a pointer to
ncalledp2.Print the value that
p1points to.Increment
n.Print the value that
p2points to.
What are printed values?
Arrays can be used as pointers#
#include <stdio.h>
char msg[] = "Welcome!";
int main() {
printf(" msg[0]: %c\n", msg[0]);
printf(" msg: %p\n", msg);
printf("*msg: %c\n", *msg);
puts("");
printf(" msg[1]: %c\n", msg[1]);
printf(" msg + 1: %p\n", msg + 1);
printf("*(msg + 1): %c\n", *(msg + 1));
}
msg[0]: W
msg: 0x591fedc2b020
*msg: W
msg[1]: e
msg + 1: 0x591fedc2b021
*(msg + 1): e
We observe:
msg[1]gives the same value as*(msg + 1).
Note that we can do pointer arithmetic like we do with other types.
We repeat our experiment with an int array:
#include <stdio.h>
int moves[] = {3, 0, 2, 8};
int main() {
printf(" moves[0]: %d\n", moves[0]);
printf(" moves: %p\n", moves);
printf("*moves: %d\n", *moves);
puts("");
printf(" moves[1]: %d\n", moves[1]);
printf(" moves + 1: %p\n", moves + 1);
printf("*(moves + 1): %d\n", *(moves + 1));
}
moves[0]: 3
moves: 0x5cab5c2f3020
*moves: 3
moves[1]: 0
moves + 1: 0x5cab5c2f3024
*(moves + 1): 0
Activity 44 (Pointer arithmetic with char vs int)
Something is odd. We added 1 to the pointer but the address increased by four 😮. What could be the reason?
Hint
What is sizeof(int)?
Activity 45 (Calculating pointer + n)
What would be the difference if you use a
double? Guess and check your answer by modifying the code above.Can you write a general formula for
pointer + non the paper using (1) the size of the data type and (2) address stored in thepointer?
Pointers can be used as arrays#
#include <stdio.h>
char msg[] = "Welcome!";
char *sptr = msg;
// same as
// char *sptr = "Welcome";
int main() {
printf(" sptr[0]: %c\n", sptr[0]);
printf(" sptr: %p\n", sptr);
printf(" *sptr: %c\n", *sptr);
puts("");
printf(" sptr[1]: %c\n", sptr[1]);
printf(" sptr + 1: %p\n", sptr + 1);
printf("*(sptr + 1): %c\n", *(sptr + 1));
puts("");
puts("using an array vs a pointer to access:");
printf(" msg[10]: %c\n", msg[10]);
// Compiler warns that 10 is past the end of array
printf(" sptr[10]: %c\n", sptr[10]);
// No warning, you can do whatever do want
// For example sptr[10000000] leads to a segmentation fault
}
sptr[0]: W sptr: 0x57cdf4390020 *sptr: W sptr[1]: e sptr + 1: 0x57cdf4390021 *(sptr + 1): e using an array vs a pointer to access: msg[10]: sptr[10]:
Pointer does not know its boundaries if used as an array, but an array variable does.
Pass by address vs pass by value#
void set_to_42(int *n); // pass by address
void set_to_58(int n); // pass by value. Value is copied and given to the function
- pass by value
the value of the argument is bound to the corresponding variable in the function typically by copying the value into a new memory region.
Activity 46 (Pass by address vs value using scalar values and array)
Implement the functions above in using the following template and use them.
Guess the output before you run your program.
#include <stdio.h>
void set_to_42(int *n) {
// YOUR CODE HERE
}
void set_to_58(int n) {
// YOUR CODE HERE
}
void set_first_element_to_58(int *arr) { // Same as int arr[]
// YOUR CODE HERE
}
int main() {
int n;
int arr[10];
// Use the first function
// YOUR CODE HERE
printf("n: %d\n", n);
// Use the second function
// YOUR CODE HERE
printf("n: %d\n", n);
// Use the third function
// YOUR CODE HERE
printf("arr[0]: %d\n", arr[0]);
}
Warning
The following argument which tries to get a pointer to the array does not make sense. An array is passed as an address anyway.
void set_first_element_to_42(int *arr[])
Note
In literature, you will also see the term pass by reference instead of pass by address. A reference in C is always an address and an address is always a pointer.
When you talk about it, use pass by reference and pass by value – every C programmer will understand it. One stands for having remote access and the other for copying the data.
However if you dig deeper, then you see that in C everything is pass by value, because the pointers are copied when a function is executed. But it is more important how objects are modified/copied and not pointers themselves.
Copying an array for passing-by-value#
Arrays are always passed by reference to functions. To create a passing-by-value effect, we have to copy it:
Programming the analogy from Activity 41.
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#define WIDTH 5
typedef enum { EMPTY, SENTENCE, PHOTO, BOTH } collage_t[WIDTH];
collage_t collage;
/**
* Wants only to write something on the first empty slot
*/
void sentence_friend(collage_t collage) {
for (size_t col = 0; col < WIDTH; ++col)
if (collage[col] == EMPTY) {
collage[col] = SENTENCE;
return;
}
}
/**
* picks a random place and puts both a sentence and a photo.
*/
void creative_friend(collage_t collage) {
for (size_t tries = 0; tries < WIDTH; ++tries) {
size_t col = rand() % WIDTH;
if (collage[col] == EMPTY) {
collage[col] = BOTH;
return;
}
}
}
/**
* Careless friend just overwrites
*/
void careless_friend(collage_t collage) { collage[rand() % WIDTH] = PHOTO; }
int main() {
// FOR DEMO: use debugger to visualize the changes
sentence_friend(collage);
creative_friend(collage);
// You copy the collage for the careless friend
collage_t collage_copy;
for (size_t col = 0; col < WIDTH; ++col)
collage_copy[col] = collage[col];
careless_friend(collage_copy);
// Then you merge the collage_copy into the collage.
}
Why did we not copy the array inside of careless_friend? Because then the storage area will not be available.