In this tutorial, we are going to learn about the basics of pointers in C.

C Pointers:

pointer is a variable that refers to a memory location, which can be an address of another variable or a valid memory address.

pointer is used to indirectly access the value referred to by a variable.

Below are a few usages of pointers :

  • To modify more than one value inside a function
  • To conveniently manipulate strings
  • To manipulate elements stored inside arrays
  • To store the address of dynamically allocated memory
  • While creating data structures, such as linked listsstacksqueues, and trees

The below two operators are exclusively used in connection with pointers:

  1. address of operator (&)
  2. indirection or dereference operator (*)

In the below code:

int x = 3;	 // Line 1
int y = 5;	 // Line 2
int *z, *k;	 // Line 3
z = &x;		 // Line 4
k = &y;		 // Line 5
int sum = *z + *k;  // Line 6

In Line 4, the address of operator (&) is used to return the address of the variable x and store it in the pointer variable z.

In Line 6, the indirection operator (*) is used to return the values stored at the addresses referred by the pointer variables z and k.

Below are a few invalid usages of & and * operators:

⟹ &10					// & cannot be used with constants, as they do not have addresses
⟹ &(a + b)				// an expression does not have any address
⟹ register int r; &r;	// it is invalid to access address of register variables
⟹ *1024				// asterisk cannot be used with constants
⟹ int n, p; p = *n;	// Unlike &, asterisk (*) cannot be used on non-pointer variables

Declaration of Pointer Variables:

The syntax for declaring a pointer variable is given below:

data_type *var1, *var2, ......, *varn;

Where data_type is any valid data type and var1, var2, …., varn are the names of the pointer variables.

The declaration informs the compiler that var1, var2, …., varn are used to store the addresses of the variables whose data type matches the current pointer’s data type.

The data_type of the pointer defines what type of variables the pointer can point to.

The size of a pointer variable varies depending on the Operating System bit architecture (i.e., 16-bit32-bit or 64-bit).

In a 16-bit OS, a pointer variable occupies 2 bytes of memory, 4 bytes in a 32-bit OS and 8 bytes in a 64-bit OS respectively.

Below are a few examples of pointer variable declarations:

int *a; // a is a pointer variable of int type which points to an address of an int value

float *f; // f is a pointer variable of float type, which points to an address of a float value

char *c; // c is a pointer variable of char type, which points to an address of a char value

Let us consider the below example:

char ch = 'A';
char *p;
p = &ch;
printf("Size of a char pointer variable = %zu\n", sizeof(p));
printf("Size of a char variable = %zu\n", sizeof(*p));

There is a difference between sizeof(p) and sizeof(*p). The sizeof(p) returns 8 bytes while sizeof (*p) returns 1 byte.

The sizeof operator on any pointer variable always returns the same value. While the sizeof operator on a *pointer_variable (meaning dereferenced pointer variable) returns the size of the data type of the variable pointed to by the pointer_variable

Parameter Passing Methods:

1. Call by value:

An argument can be passed to a function in any of the below two ways:

  1. By sending the value of the argument
  2. By sending the address of the argument

When a function is called by passing values directly, such function calls are referred as call by value.

In a call by value scenario, the value of each actual argument in the calling function is copied into the corresponding formal parameters of the called function.

In such cases, any changes made to the formal parameters in the called function do not reflect back in the calling function.

Let’s consider an example code:

#include <stdio.h>
void swap(int, int);
void main() {
  int a = 5;
  int b = 10;
  printf("Before swapping in main : a = %d \t b = %d\n", a, b);
  swap(a, b);
  printf("After swapping in main : a = %d \t b = %d\n", a, b);
}
void swap(int x, int y) {
  int t;
  t = x;
  x = y;
  y = t;
  printf("After swapping in swap : x = %d \t y = %d\n", x, y);
}

Output:

Before swapping in main : a = 5 	 b = 10
After swapping in swap : x = 10 	 y = 5
After swapping in main : a = 5 	     b = 10

The above code has a swap() method with two arguments of type int pointers. The void is a keyword and is used when a method does not return any value. The swap() method takes two int variables x, y and they are assigned with the values of a and b.

A temporary variable of type int is declared t. It is used to store the temporary value when the values are swapped.

2. Call by address:

While calling a function, if we pass the address of a variable as an argument to a function, it is known as call by address.

In such scenarios, we should declare the parameters in the called function as pointer variables.

The addresses of actual arguments in the calling function are copied into the pointer variables of formal parameters of the called function.

Using the addresses, the called function can access the actual arguments from the formal parameters. Meaning, the code inside the called function can directly access and modify the actual arguments in the calling function.

Let’s consider an example code:

#include <stdio.h>
void swap(int *, int *);
void main() {
  int a = 5;
  int b = 10;
  printf("Before swapping in main : a = %d \t b = %d\n", a, b);
  swap(&a, &b);
  printf("After swapping in main : a = %d \t b = %d\n", a, b);
}
void swap(int *x, int *y) {
  int t;
  t = *x;
  *x = *y;
  *y = t;
  printf("After swapping in swap : *x = %d \t *y = %d\n", *x, *y);
}

Output:

Before swapping in main : a = 5 	 b = 10
After swapping in swap : *x = 10 	 *y = 5
After swapping in main : a = 10 	 b = 5

This statement declares a swap() method with two arguments of type int. The void keyword is used, when a method does not return any value. In this method call, we pass two parameters &a&b. These addresses are assigned to the pointer variables *x*y in the method.

It takes two arguments of type int pointers *x*y. These pointers are assigned with addresses of ab i.e., 11111234 respectively. This method does not return anything so the keyword void is used as a return type. A temporary variable t is declared of type int.
It will be used to store a temporary value when the values are swapped.

Note: ‘&‘ returns the address of the variable.

References:

Happy Learning 🙂