C Program For Matrix Multiplication Using Pointers
Matrix multiplication is a fundamental operation in linear algebra, widely used across various fields of computing. Handling matrices efficiently, especially large ones, often requires dynamic memory allocation, for which pointers in C are an excellent tool.
In this article, you will learn how to implement matrix multiplication in C using pointers, focusing on dynamic memory allocation and clear program structure.
Problem Statement
Multiplying two matrices, A (of size M x N) and B (of size N x P), results in a new matrix C (of size M x P). Each element C[i][j] is the dot product of the i-th row of A and the j-th column of B. This operation requires careful management of array indexing and memory, particularly when matrix dimensions are not known at compile time or when dealing with large datasets that exceed stack memory limits. Using fixed-size 2D arrays can lead to wasted memory or stack overflow errors, making dynamic allocation with pointers a robust solution.
Example
Consider two 2x2 matrices, A and B:
Matrix A:
1 2
3 4
Matrix B:
5 6
7 8
To calculate the resulting matrix C (A x B):
- C[0][0] = (A[0][0] * B[0][0]) + (A[0][1] * B[1][0]) = (1*5) + (2*7) = 5 + 14 = 19
- C[0][1] = (A[0][0] * B[0][1]) + (A[0][1] * B[1][1]) = (1*6) + (2*8) = 6 + 16 = 22
- C[1][0] = (A[1][0] * B[0][0]) + (A[1][1] * B[1][0]) = (3*5) + (4*7) = 15 + 28 = 43
- C[1][1] = (A[1][0] * B[0][1]) + (A[1][1] * B[1][1]) = (3*6) + (4*8) = 18 + 32 = 50
Resulting Matrix C:
19 22
43 50
Background & Knowledge Prerequisites
To effectively understand this article, readers should be familiar with:
- C Language Basics: Variables, data types, loops (
for), conditional statements (if). - Pointers in C: Understanding pointer declaration, dereferencing (
*), and pointer arithmetic. - Dynamic Memory Allocation: Functions like
mallocandfreefor allocating and deallocating memory at runtime. - 2D Arrays in C: How 2D arrays are stored in memory and accessed.
Use Cases or Case Studies
Matrix multiplication is a cornerstone operation in various computational domains:
- Image Processing: Filters for blurring, sharpening, edge detection, and other transformations are often implemented as matrix multiplications.
- 3D Graphics: Core operations like translation, rotation, scaling, and projection of 3D objects rely heavily on matrix multiplication to transform vertices in space.
- Machine Learning: Neural networks extensively use matrix multiplication for forward and backward propagation steps, particularly in deep learning models where layers are represented as matrices.
- Scientific Simulations: Solving systems of linear equations, finite element analysis, and quantum mechanics simulations frequently involve large-scale matrix operations.
- Cryptography: Certain cryptographic algorithms and hash functions utilize matrix operations for data transformation and key generation.
Solution Approaches
Implementing matrix multiplication with pointers involves dynamically allocating memory for each matrix, filling them with values, performing the multiplication, and finally deallocating the memory.
Dynamic Matrix Multiplication Using Pointers
This approach uses pointers to pointers (int**) to create matrices dynamically, allowing for flexible dimensions and efficient memory usage.
One-line summary: Dynamically allocate 2D matrices using malloc, perform standard matrix multiplication, and then free the allocated memory to prevent leaks.
Code example:
// Matrix Multiplication using Pointers
#include <stdio.h> // For input/output operations (printf, scanf)
#include <stdlib.h> // For dynamic memory allocation (malloc, free)
// Function to allocate memory for a matrix
int** allocateMatrix(int rows, int cols) {
int** matrix = (int**)malloc(rows * sizeof(int*)); // Allocate memory for rows
if (matrix == NULL) {
printf("Memory allocation failed for matrix rows!\\n");
exit(1); // Exit if allocation fails
}
for (int i = 0; i < rows; i++) {
matrix[i] = (int*)malloc(cols * sizeof(int)); // Allocate memory for columns in each row
if (matrix[i] == NULL) {
printf("Memory allocation failed for matrix columns!\\n");
// Free previously allocated row pointers before exiting
for (int j = 0; j < i; j++) {
free(matrix[j]);
}
free(matrix);
exit(1);
}
}
return matrix;
}
// Function to free memory allocated for a matrix
void freeMatrix(int** matrix, int rows) {
for (int i = 0; i < rows; i++) {
free(matrix[i]); // Free memory for each row
}
free(matrix); // Free memory for the array of row pointers
}
// Function to read matrix elements from user
void readMatrix(int** matrix, int rows, int cols, char name) {
printf("Enter elements for Matrix %c (%dx%d):\\n", name, rows, cols);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("Enter element [%d][%d]: ", i, j);
scanf("%d", &matrix[i][j]);
}
}
}
// Function to print a matrix
void printMatrix(int** matrix, int rows, int cols, char name) {
printf("\\nMatrix %c (%dx%d):\\n", name, rows, cols);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%5d ", matrix[i][j]);
}
printf("\\n");
}
}
int main() {
int rows1, cols1, rows2, cols2;
// Step 1: Get dimensions for Matrix A from user
printf("Enter dimensions for Matrix A (rows cols): ");
scanf("%d %d", &rows1, &cols1);
// Step 2: Get dimensions for Matrix B from user
printf("Enter dimensions for Matrix B (rows cols): ");
scanf("%d %d", &rows2, &cols2);
// Step 3: Check if multiplication is possible
if (cols1 != rows2) {
printf("Error: Number of columns in Matrix A must be equal to number of rows in Matrix B.\\n");
return 1; // Indicate error
}
// Step 4: Dynamically allocate memory for matrices
int** matrixA = allocateMatrix(rows1, cols1);
int** matrixB = allocateMatrix(rows2, cols2);
int** resultMatrix = allocateMatrix(rows1, cols2); // Result matrix will be rows1 x cols2
// Step 5: Read elements for Matrix A and Matrix B
readMatrix(matrixA, rows1, cols1, 'A');
readMatrix(matrixB, rows2, cols2, 'B');
// Step 6: Print original matrices
printMatrix(matrixA, rows1, cols1, 'A');
printMatrix(matrixB, rows2, cols2, 'B');
// Step 7: Perform matrix multiplication
printf("\\nPerforming matrix multiplication...\\n");
for (int i = 0; i < rows1; i++) {
for (int j = 0; j < cols2; j++) {
resultMatrix[i][j] = 0; // Initialize element
for (int k = 0; k < cols1; k++) { // Or k < rows2, since cols1 == rows2
resultMatrix[i][j] += matrixA[i][k] * matrixB[k][j];
}
}
}
// Step 8: Print the result matrix
printMatrix(resultMatrix, rows1, cols2, 'C'); // C for result
// Step 9: Free allocated memory
freeMatrix(matrixA, rows1);
freeMatrix(matrixB, rows2);
freeMatrix(resultMatrix, rows1);
printf("\\nMemory deallocated successfully.\\n");
return 0; // Indicate successful execution
}
Sample output:
Enter dimensions for Matrix A (rows cols): 2 2
Enter dimensions for Matrix B (rows cols): 2 2
Enter elements for Matrix A (2x2):
Enter element [0][0]: 1
Enter element [0][1]: 2
Enter element [1][0]: 3
Enter element [1][1]: 4
Enter elements for Matrix B (2x2):
Enter element [0][0]: 5
Enter element [0][1]: 6
Enter element [1][0]: 7
Enter element [1][1]: 8
Matrix A (2x2):
1 2
3 4
Matrix B (2x2):
5 6
7 8
Performing matrix multiplication...
Matrix C (2x2):
19 22
43 50
Memory deallocated successfully.
Stepwise explanation:
- Include Headers:
stdio.hfor standard input/output andstdlib.hfor dynamic memory allocation functions (malloc,free,exit). allocateMatrixFunction:- Takes
rowsandcolsas input.
- Takes
int* pointers, where each pointer will point to a row. This is the first level of allocation.ints for the actual column data. This is the second level of allocation.malloc failures.int** to the dynamically created matrix.freeMatrixFunction:- Takes the matrix (
int**) and itsrowsas input.
- Takes the matrix (
readMatrixFunction: Prompts the user to enter elements for a given matrix using nested loops andscanf.printMatrixFunction: Prints the elements of a given matrix in a formatted way.mainFunction:- Declares variables for matrix dimensions.
allocateMatrix to dynamically create matrixA, matrixB, and resultMatrix.readMatrix to fill matrixA and matrixB with user-provided values.printMatrix to display the entered matrices.for loops.i for rows of A, j for columns of B) iterate through each element of the resultMatrix.k) calculates the dot product: resultMatrix[i][j] is accumulated by summing matrixA[i][k] * matrixB[k][j].resultMatrix.freeMatrix for all dynamically allocated matrices to release memory back to the system. This step is critical for good memory hygiene.Conclusion
Implementing matrix multiplication using pointers in C provides a powerful and flexible way to handle matrices of varying sizes, especially when dimensions are determined at runtime. Dynamic memory allocation with malloc and free ensures efficient memory usage and prevents common issues like stack overflow. By understanding the core logic of matrix multiplication combined with C's pointer capabilities, developers can create robust and scalable solutions for complex mathematical operations.
Summary
- Matrix multiplication involves computing the dot product of rows and columns, resulting in a new matrix.
- Pointers in C, specifically pointers to pointers (
int**), allow for dynamic memory allocation of 2D matrices. - Dynamic allocation is crucial for handling matrices whose dimensions are unknown at compile time or for very large matrices.
- The
mallocfunction is used to allocate memory for rows and then for columns within each row. - Memory must be explicitly freed using
freefor each allocated block (rows first, then the array of row pointers) to prevent memory leaks. - The core multiplication logic involves three nested loops, iterating through rows of the first matrix, columns of the second, and the common dimension.
- Error handling for incompatible matrix dimensions and failed memory allocations is important for robust programs.