Pointer vs Arrays


  • Recap : Pointers refer to memory addresses
    • Pointer arithmetic useful for array traversal
  • Recap : Arrays are Contiguous memory blocks
    • Array names decay to pointers to the first element
    • Array name is constant referring to the address of array
    • Array name behaves like a pointer in certain ways
    • (arr + i) gives address of ith element of array

Pointer Arithmetic


ptr++

  • Take me to next cell
  • Useful for traversing arrays sequentially

ptr--

  • Decrements the pointer to previous element

+, +=

  • Adding integer moves pointer ahead by that amount
  • Helps jump around array without index

-, -=

  • Subtracting integer moves pointer backward
int arr[5] = {1,2,3,4,5}; 
int* ptr = arr; //ptr points to arr[0]
 
ptr++; //now points to arr[1]  // not useful operation
 
ptr += 2; //points to arr[3]
ptr - 2; //points back to arr[1]
 
int offset = ptr - arr; //distance between pointers
  • Incrementing pointer traverses array
  • Adding/subtracting integers moves pointer
  • Subtracting pointers gives distance/offset

Example:

#include<iostream>
using namespace std;
 
int main(){
	
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	
	int *ptr = arr; // Read only pointer 
	
	// Traverse
	for(int i=0; i<4; i++){
		cout << ptr << " Data " << *(ptr) << endl;
		ptr = ptr + 1;
	}
	
	//reset to begining of the array
	ptr = arr; 
	
	// Print
	for(int i=0; i<10; i++){
		cout << *(arr + i) << " , "; // arr[i] // using dereference operator
	}
	
	return 0;
}

NOTE

  • ptr1 + ptr2 : doesn’t make any sense
  • ptr1 - ptr2 : does makes sense for arrays

Pointers to Arrays


We can have pointers to individual elements or the entire array:

int arr[10] = {1,2,3,4,5,6,7,8,9,10}; 
 
// Pointer to single element  
int* p1 = arr; 
 
// Pointer to entire array
int (*ptr)[10] = &arr; 

Pointer to Element

This points to the single element:

p1++; // Points to arr[1]
 
cout << p1 << endl;  
cout << *p1 << endl;

Pointer to Array

This points to the whole array:

cout << "Address of Array: " << ptr << endl;

Can get next array address:

cout << ptr + 1 << endl; 

Jumps by complete array size (not just 1 element).

Dereferencing

Gives access to array:

cout << (*ptr)[0] << endl; // Element arr[0]  

Example:

#include<iostream>
using namespace std;
 
int main(){
	
	int arr[10] = {1,2,3,4};
	
	cout << arr << endl;
	cout << &arr << endl;
	cout << arr + 1 << endl;
	
	// Pointer to 0th element of the array 
	int * p1 = arr;
	p1++;
	
	cout << p1 << endl;
	cout << (*p1) << endl;
	
	// Pointer to the entire array 
	int (*ptr)[5]; // Pointer to an array of 5 elements
	ptr = &arr;
	
	cout << "Pointer to Array " << ptr << endl;
	
	cout << ptr << endl;
	cout << ptr + 1 << endl; // location after the array 
	// address jump will be of 40 bytes
	
	// int *ptr[5]; // Any array of pointer of size 5
	
	return 0;
}

Dereferencing Pointers to Arrays


We can have a pointer to an individual element or the entire array:

int arr[5] = {1,2,3,4,5};
 
// Pointer to single element
int* ptr1 = arr; 
 
// Pointer to entire array
int (*ptr2)[5] = &arr;

Dereferencing Element Pointer

This gives the element value:

cout << *ptr1; // Prints 1

Can access elements like array:

ptr1[0]; // 1
ptr1[1]; // 2

Dereferencing Array Pointer

This gives the array itself:

cout << (*ptr2)[0]; // Prints 1  
cout << (*ptr2)[1]; // Prints 2

Essentially simplifies array syntax:

(*ptr2)[i]; // Same as arr[i]

We dereference array pointer and can use like a normal array.

The array pointer will increment by the size of array (not by 1 element).

Example:

#include<iostream>
using namespace std;
 
int main(){
	
	int arr[10] = {1,2,3,4};
	
	cout << arr << endl;
	cout << &arr << endl;
	cout << arr + 1 << endl;
	
	// Pointer to 0th element of the array 
	int * p1 = arr;
	p1++;
	
	cout << p1 << endl;
	cout << (*p1) << endl;
	
	// Pointer to the entire array 
	int (*ptr)[5]; // Pointer to an array of 5 elements
	ptr = &arr;
	
	cout << "Pointer to Array " << ptr << endl;
	
	cout << ptr << endl;
	cout << ptr + 1 << endl; // location after the array 
	// address jump will be of 40 bytes
	
	// int *ptr[5]; // Any array of pointer of size 5
	
	// Dereferencing the pointer to an array 
	cout << (*p1) << endl // a[0]
	cout << (*ptr) << endl; // arr 
	
	return 0;
}

Row Pointers in 2D Arrays


In a 2D array, each element is actually a 1D array representing a row. Rows are stored sequentially in memory(Row major form).

int arr[3][4]; // 3 rows, 4 cols

This can be visualized as an array of row pointers:

arr --> [row1] -> [row2] -> [row3]

Where:

  • arr - Pointer to first row
  • row1, row2, row3 - Pointers to each row array

The array name arr itself acts as a pointer to the first row:

int (*row1)[4] = arr;

We can traverse rows by incrementing the array name:

cout << arr << endl; // Address of row1
cout << arr+1 << endl; // Address of row2
cout << arr+2 << endl; // Address of row3

Accessing Elements

To access any element arr[i][j]:

1. Index row pointer to get row 
2. Index into that row to get element

Example:

#include<iostream>
using namespace std;
 
int main(){
	
	// Pointers and 2D Arrays (Multi-Dimension Arrays)
	int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
	
	cout << "Arr "<< arr << endl;
	cout << "Address of the 0,0 element " << &arr[0][0] << endl;
	cout << "Address of the 0,1 element " << &arr[0][1] << endl;
	cout << "Arr + 1 " << arr + 1 << endl; // Row pointer which jumps to next row
	cout << "Address of the 1,0 element " << &arr[1][0] << endl;
	
	return 0;
}

2D Arrays and Pointer


In a 2D array, each element itself is a 1D array representing a row. 2D arrays are stored in row-major order in memory.

int arr[3][4] = {  
  {1, 2, 3, 4}, 
  {5, 6, 7, 8},
  {9, 10, 11, 12}
};
  • arrΒ - Pointer to first row array
  • arr[0]Β - Pointer to first element of first row

The array name decays into a pointer to the first row:

cout << arr; // Prints address of first row

Passing 2D Arrays to Functions

#include<iostream>
using namespace std;
 
// Method 1 - Using pointer to array  
void accept2DArray(int (*ptr)[4]){
	cout << "Address of Row 0 " << ptr << endl;
	cout << "Address of Row 1 " << ptr + 1 << endl;
	
	int i = 1;
	int j = 2;
	
	cout << "Row 1, Col 2: " << *(*(ptr+i) + j) << endl;
	cout << "Row 1, Col 2: " << ptr[i][j] << endl;
}
 
// Method 2 - Using 2D array syntax 
void printArray2(int arr[][4]) { 
	cout << "Row 2, Col 3: " << arr[2][3] << endl; 
}
 
 
int main(){
	
	// Pointers and 2D Arrays (Multi-Dimension Arrays)
	int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
	
	// Pass as pointer 
	accept2DArray(arr);
	
	// Pass using array syntax 
	printArray2(arr);
	
	return 0;
}

The output of this would be:

Row 1, Col 2: 7
Row 2, Col 3: 12

NOTE

  • arrΒ decays to a pointer to the first row
  • Both methods allow accessing any element arr[i][j]