0

This is a code for multiplying two square matrices in C.

What is the difference between using malloc and calloc in void multiply() function? When using malloc, I am getting garbage values, but calloc is providing the right answer. Only the first row is outputting garbage values so is it an issue with the way malloc allocates space in the heap as compared to calloc?

#include <stdio.h>
#include <stdlib.h>

int *getArray(int);
void display(int *, int, int);
void multiply(int *, int *, int);

int main() {
    int n;
    printf("enter dimension of square matrix:\n");
    scanf("%d", &n);
    int *arr1;
    int *arr2;
    arr1 = getArray(n);
    display(arr1, n, n);
    printf("\n now give input for next array");
    arr2 = getArray(n);
    display(arr2, n, n);
    printf("\n\n\n");
    multiply(arr1, arr2, n);
    return 0;
}

int *getArray(int n) {
    int *arr = (int *)malloc(n * n * sizeof(int));
    printf("\n");
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            scanf("%d", (arr + i * n + j));
        }
    }
    /*for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            printf(" %d ", *(arr + i * n + j));
        }
        printf("\n");
    }*/
    return arr;
}
    
void display(int *arr, int row, int col) {
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            printf(" %d ", *(arr + i * row + j));
        }
        printf("\n");
    }
}

void multiply(int *arr1, int *arr2, int n) {
    int *arr = (int *)calloc(n * n, sizeof(int));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            for (int k = 0; k < n; k++) {
                *(arr + i * n + j) += (*(arr1 + i * n + k)) * (*(arr2 + k * n + j));
            }
        }
    }
    printf("product of above matrices = \n\n");
    display(arr, n, n);
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • 3
    Using `malloc()`, the allocated memory is not initialized; using `calloc()`, the allocated memory is initialized to all bytes zero. – Jonathan Leffler Jul 15 '20 at 11:25
  • In your case there is no functional difference as you initialize the memory. But using `calloc` here means unnecessary setting to zero by `calloc`. – Paul Ogilvie Jul 15 '20 at 11:33
  • Does this answer your question? [Difference between malloc and calloc?](https://stackoverflow.com/questions/1538420/difference-between-malloc-and-calloc) – Chase Jul 15 '20 at 12:17
  • `calloc(n*n,sizeof(int)` does not overflow the size calculation as readily as `malloc(n*n*sizeof(int))`. Better to use `malloc(sizeof(int)*n*n*)` with `malloc()`. – chux - Reinstate Monica Jul 15 '20 at 15:13
  • 1
    @chux-ReinstateMonica: actually both calls pose problems if `n * n` exceeds the range of type `int`, they just fail in different ways. `malloc(sizeof(int) * n * n)` is definitely better and `calloc((size_t)n * n, sizeof(int))` is advisable too. – chqrlie Jul 15 '20 at 17:14

1 Answers1

1

The only functional difference between allocating memory with malloc() and with calloc() for the same size, assuming the size computation is accurate, is the latter initializes the block to all bits 0, whereas the former does not.

All bits 0 means all int values in the array are initialized to 0.

The inner loop in the multiply function only increments the element at row i and column j, therefore the function relies on implicit initialization of the array elements to 0. calloc() does that, but not malloc() so you definitely need to use calloc().

Also note these remarks:

  • in display the computation for the offset of the matrix element at row i column j should be printf(" %5d ", *(arr + i * col + j));
  • multiply should return arr and display() should be called in the main function.
  • you should check for scanf(), malloc() and calloc()` failure
  • you should free allocated memory
  • pointer arguments to objects that are not modified by the function should be const qualified so the function can be called with a pointer to a const object.

Here is a modified version:

#include <stdio.h>
#include <stdlib.h>

int *getArray(int);
void display(const int *, int, int);
int *multiply(const int *, const int *, int);

int main() {
    int n;
    printf("enter dimension of square matrix:\n");
    if (scanf("%d", &n) != 1)
        return 1;
    printf("\n now give input for the first array");
    int *arr1 = getArray(n);
    if (!arr1)
        return 1;
    display(arr1, n, n);
    printf("\n now give input for the second array");
    int *arr2 = getArray(n);
    if (!arr2)
        return 1;
    display(arr2, n, n);
    printf("\n\n\n");
    int *arr = multiply(arr1, arr2, n);
    if (!arr)
        return 1;
    printf("product of above matrices = \n\n");
    display(arr, n, n);
    free(arr1);
    free(arr2);
    free(arr);
    return 0;
}

int *getArray(int n) {
    int *arr = malloc(sizeof(int) * n * n);
    if (arr == NULL)
        return NULL;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (scanf("%d", (arr + i * n + j)) != 1) {
                free(arr);
                return NULL;
            }
        }
    }
    return arr;
}
    
void display(const int *arr, int row, int col) {
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            printf(" %5d ", *(arr + i * col + j));
        }
        printf("\n");
    }
}

int *multiply(const int *arr1, const int *arr2, int n) {
    int *arr = calloc((size_t)n * n, sizeof(int));
    if (arr == NULL)
        return NULL;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            for (int k = 0; k < n; k++) {
                *(arr + i * n + j) += (*(arr1 + i * n + k)) * (*(arr2 + k * n + j));
            }
        }
    }
    return arr;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • what is the role of using const? also, thank you @chqrlie for the answer. – Siddharth Kolipara Jul 16 '20 at 10:49
  • 1
    @SiddharthKolipara: in a function definition, pointer arguments to objects that are not modified by the function should be `const` qualified so the function can be called with a pointer to a `const` object. For example `strcpy()` is declared as `char *strcpy(char *s1, const char *s2);` because the contents of the array pointed to by `s2` are not modified, but the destination array pointed to by `s1` is, and is returned. – chqrlie Jul 16 '20 at 17:15