Skip to content

Instantly share code, notes, and snippets.

@eburdon
Last active February 24, 2017 15:59
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Embed
What would you like to do?
A Review of C pointers | Basic, Arrays, Structs, Function
#include <stdio.h>
#include <string.h>
// Declare a typedef for useful_function
typedef int (*FUNC_PTR)(int);
// Parameter is the signature of the method we will pass in
void int_ptr_function(int (*param)(int)) {
printf("[BB] This statement is executed AFTER the parameter function is evaluated!\n");
printf("[BB]: Value of function_param is %d\n", param);
}
void typedef_ptr_function(FUNC_PTR func_parameter) {
printf("[CC] This statement is executed AFTER the parameter function is evaluated!\n");
printf("[CC] Value of function_param is %d\n", func_parameter);
}
// Takes an integer parameter
int simple_int_function(int param) {
printf("[AA]: Value of param is %d\n", param);
return param;
}
/**
* A pointer review for the devs who can't QUITE remember the
* tricks.
*
* For more details, I recommend reading "Everything you need to know
* about pointers in C" by Peter Hosey. Found here:
* http://boredzo.org/pointers/
*
* This demo borrows a lot of their code, but is provided here as a
* ready-to-run tutorial. It also has a lot of experiments as "proofs"
* of how these things work.
* */
int main(void) {
/* ****************** *
* Basic Pointers
* ****************** */
printf("\nBasic Pointers\n\n");
// Declare a variable; it occupies some memory
int var = 23;
printf("[1] %d\n", var);
// & is the "address-of-operator"
// Create an int pointer that points to var
int *var_ptr = &var;
// The VALUE of the ptr is the ADDRESS of var ...
printf("[2] %p == %p\n", &var, var_ptr);
// ... and has it's own unique ADDRESS
printf("[3] %p\n", &var_ptr);
// The * operator dereferences (GETS) the value in the address!
printf("[4] %d\n", *var_ptr);
// If we change var, we expect the value of var_ptr to change as well
var = 55;
printf("[5] %d == %d\n", var, *var_ptr);
// If we change var_ptr, we expect the value of var to change as well
*var_ptr = 22;
printf("[6] %d == %d\n", *var_ptr, var);
// NOTE: assigning a value directly to the pointer will cause a crash!
// This changes the ADDRESS of the pointer, not the value!
// Uncomment the block below and notice the failure.
/* var_ptr = 8;
printf("%d == %d\n", var, *var_ptr);
printf("We won't print this line with the above 2 lines un-commented"); */
/* ****************** *
* Arrays
* ****************** */
printf("\nArray Logic\n\n");
// This array has three 'ints' worth of space
int array[] = { 45, 67, 89 };
// Thanks to decay, using the `array` name itself POINTS to the address
// of the first element. This means array expressions work a lot like
// pointers!
printf("[7] %p == %p\n", array, &array[0]);
// dereferencing the array is the same as getting the first value explicitly
printf("[8] %d == %d\n", *array, array[0]);
// However, array arithmetic doesn't work like pointer arithmetic
// (increment pointer after accessing).
// attempting *(array++) will crash
int *array_ptr = array;
printf("[9] first element: %d\n", *(array_ptr++));
printf("[10] second element: %d\n", *(array_ptr++));
printf("[11] third element: %d\n", *array_ptr);
// Note: due to decay, you can point a var at any "index" of the arrray
// Doing the following loses the references to the FIRST 'array' value
int *array_ptr_two = &array[1];
printf("[12] %d\n", array_ptr_two[0]);
printf("[13] %d\n", array_ptr_two[1]);
/* ****************** *
* Structs & Unions
* ****************** */
printf("\nStruct & Union Logic\n\n");
struct mystruct {
int answer;
};
// Basic access of a member
struct mystruct data;
data.answer = 42;
printf("[14]: %d\n", data.answer);
// How many ways can we access and assign struct members?
struct mystruct *struct_ptr = &data;
// 01: Standard "address-of" and * operators
// print the ADDRESS and VALUE of the member
printf("[15]: %p\n", &(*struct_ptr).answer);
printf("[16]: %d\n", (*struct_ptr).answer);
// update
(*struct_ptr).answer = 01;
printf("[17]: %d\n", (*struct_ptr).answer);
// 02: "pointer-to-member" operator
struct_ptr->answer = 22;
printf("[18]: %d\n", struct_ptr->answer);
// 03: Multiple indirection
// Let us create a pointer who points to another pointer
struct mystruct **struct_ptr_ptr = &struct_ptr;
// I can access the value stored in the pointer's pointer directly...
printf("[20]: %d\n", (**struct_ptr_ptr).answer);
// ... or by the (pointer to pointer)-to-member operator
printf("[21]: %d\n", (*struct_ptr_ptr)->answer);
printf("\n");
// What if we have decaying arrays in our struct?
struct myemail {
char message[3];
} email = {
{"HI!"}
};
// Recall you print a single member vs entire char array using the formatter
printf("[22]: %c vs %s\n", email.message[0], email.message);
// You can also print from the middle of an array with the address operator
printf("[23]: %s\n", &email.message[1]);
// Create a pointer to the struct; How to access the values now?
struct myemail *email_ptr = &email;
// Exactly the same as before!
printf("[24]: %c vs %c vs %s\n", (*email_ptr).message[0], email_ptr->message[1], email_ptr->message);
/* ****************** *
* Function Pointers
* ****************** */
printf("\nFunction Pointers\n\n");
// Like vars, functions have addresses too! You can point a matching
// signature to an existing address
int (*func_ptr)(int);
func_ptr = &simple_int_function;
// You can invoke this function with pointer
simple_int_function(11);
(*func_ptr)(22);
printf("\n");
// Why the heck are these useful?
// You can pass functions as parameters to other functions!
// Create a function with the parameter type matching the signature of the
// func you want to pass in.
int_ptr_function((*func_ptr)(33));
printf("\n");
// For readbility, you can declare the function with a typdef'd method
// signature
typedef_ptr_function((*func_ptr)(44));
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment