Programming in C

Pointers

Gerald Senarclens de Grancy

Purpose of Pointers

Which Problems do Pointers Solve?

  • Pass arrays to functions
  • Increases performance when passing large data structures to functions
  • Using pointers improves performance for repetitive operations (eg. iteration)
  • Function pointers
  • Change parameter values from a function
  • Prerequisite for using memory from the heap (free store)
  • Necessary for implementing high level data structures (linked lists, trees, ...)

Which Problems do Pointers Cause?

  • Prone to bugs
  • Syntax can be hard to read and understand
  • Modifying parameters breaks functional programming paradigm (const Type*)
Many of these problems are solved by C++ and higher level languages

Definition

  • A pointer stores the memory address of a variable
  • Pointers can point to other pointers
  • Obtaining the value stored at a pointer's address: * (de-reference operator)
  • Getting the address of a variable: & (address-of operator)
  • C pointers

Working with Pointers

Declaration

Type* ptr;

Pointers should be initialized as NULL pointers

Type* ptr = NULL;

Changing a Variable Through a Pointer

int a = 5;
int* a_ptr = &a;
*a_ptr += 5;

Complete Program

#include <stdio.h>

int main() {
int a = 5;
int* a_ptr = &a; // &: address-of operator
*a_ptr += 5; // *: dereference operator
printf("updated value: %d (at %p - %zu bytes)\n", a, a_ptr, sizeof(a_ptr));
return 0;
}

source/c/pointers/basics.c

Pointer to a Pointer

#include <stdio.h>

int main() {
int a = 4, b = 5;
int* a_ptr = &a; // when starting, it is easiest to have a pre- or suffix
int* b_ptr = &b; // for every pointer in your programs
int** p = &a_ptr;
*p = NULL; // set a_ptr to invalid location
*p = b_ptr;
**p *= **p; // use multiple lines to make readable
printf("a = %d, b = %d\n", a, b);
return 0;
}

source/c/pointers/pointer_to_pointer.c

Examples

Update Function Parameters

Avoid changing parameters whenever possible!

#include <stdio.h>

void update(int* a_ptr,int *b_ptr) {
*a_ptr += 10; // assign new value to memory address of `a`
*b_ptr = 100; // assign new value to `b`
// still possible to return a value if needed
}

int main() {
int a=4;
int b=5;
int* a_ptr = &a; // &: address-of operator
update(a_ptr, &b);
printf("updated values: %d %d\n", a, b);
return 0;
}

source/c/pointers/update_parameters.c

Iterate Over an Array

#include <stdio.h>

int sum(const int* array, int count) {
int value = 0;
while (count--) {
value += *array++;
}
return value;
}

int main() {
int array[] = {1, 2, 3, 4, 5, 6};
int value = sum(array, 6);
printf("sum: %d\n", value);
return 0;
}

source/c/pointers/array.c

Pointer to Struct

The arrow operator -> allows direct access to members when using pointers.

#include <stdio.h>
typedef struct {int year; int month; int day;} IsoDate;

void print_date(const IsoDate* d) {
printf("%04d-%02d-%02d\n", (*d).year, d->month, d->day);
}

int main() {
IsoDate date = {2022, 1, 11};
print_date(&date);
return 0;
}

source/c/pointers/struct.c

String Operations

#include <stdio.h>
#include <ctype.h>

void upper(char* text) {
while (*text) { // string ends with the `\0` character
*text = toupper(*text); // return upper case character
text++;
}
}

int main() {
char name[] = "Chris";
upper(name);
printf("%s\n", name);
return 0;
}

source/c/pointers/string.c

Questions
and feedback...