Pointer to object#

Object#

object

region of data storage that can represent values

For example:

int number = 42;
char name[] = "Partha";
  • number is the identifier of the object 42. 42 is stored in an data storage area of 4 bytes.

  • name is 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;

    
🤔 Question to ponder

Do you remember

  1. what the arrow tips (directions) mean?

  2. an example where a function writes to its arguments?

Meaning#

https://upload.wikimedia.org/wikipedia/commons/b/b4/Pointers.svg

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

pointer

an object that stores a memory address

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: 0x7ffdca90d08c

 a: 0x7ffdca90d08c
*a: 42
&a: 0x7ffdca90d080

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#

Table 2 Pointer operators#

Operator

Meaning

Example

*

dereference

*a gives the value which is stored at the address stored in the pointer variable a.

&

address of

&b gives the address of the value variable b.

Activity 42 (Meaning of pointer operators)

Which are correct for the code above?

  1. a == 42

  2. *a == 42

  3. &a == 42

  4. &*b == 42

  5. *&b == 42

Activity 43 (Declaring and using a pointer)

Code the following:

  1. Declare and initialize an unsigned number called n.

  2. Declare and initialize a pointer to n called p1.

  3. Declare and initialize a pointer to n called p2.

  4. Print the value that p1 points to.

  5. Increment n.

  6. Print the value that p2 points 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: 0x570edd076020
*msg: W

 msg[1]: e
 msg + 1: 0x570edd076021
*(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: 0x55e8bb743020
*moves: 3

 moves[1]: 0
 moves + 1: 0x55e8bb743024
*(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)

  1. What would be the difference if you use a double? Guess and check your answer by modifying the code above.

  2. Can you write a general formula for pointer + n on the paper using (1) the size of the data type and (2) address stored in the pointer?

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: 0x5c16a679e020
 *sptr: W

  sptr[1]: e
  sptr + 1: 0x5c16a679e021
*(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 address

a parameter passing method where the address of the argument is passed.

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)

  1. Implement the functions above in using the following template and use them.

  2. 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:

⚡ Live programming

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.