Search code examples
cpointersmatrixmalloc

wrong values when displayed : C pointer or malloc issue?


My program multiplies a matrix 1 by a matrix 2. The matrix 3 is the result. I can display matrix 1 and matrix 2 with the correct values but I am not able to display though the same function the expected values of matrix 3, although the calculated values are good.

here my code which can compile.

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

struct Dimensions {
    int dim1, dim2;
};

struct Dimensions enterDimensions(void);

int **createMatrix(int, int);

void deleteMatrix(int **);

void displayMatrix(int **, int, int);

int **multiply(int **, int **, int, int, int);

int main(void) {
    struct Dimensions dimensions1 = enterDimensions();
    int **matrix1 = createMatrix(dimensions1.dim1, dimensions1.dim2);
    displayMatrix(matrix1, dimensions1.dim1, dimensions1.dim2);
    struct Dimensions dimensions2 = enterDimensions();
    int **matrix2 = createMatrix(dimensions2.dim1, dimensions2.dim2);;
    displayMatrix(matrix2, dimensions2.dim1, dimensions2.dim2);

    if (dimensions1.dim2 != dimensions2.dim1) {
        printf("the product of these matrixes does not exist");
    } else {
        int **matrix3 = multiply(matrix1, matrix2, dimensions1.dim1, dimensions1.dim2, dimensions2.dim2);
        displayMatrix(matrix3, dimensions1.dim1, dimensions2.dim2);
        deleteMatrix(matrix3);
    }

    deleteMatrix(matrix1);
    deleteMatrix(matrix2);

    return 0;
}

struct Dimensions enterDimensions(void) {
    int dim1;
    int dim2;
    struct Dimensions dimensions;
    printf("dim 1 : \n");
    scanf("%d", &dim1);
    printf("dim 2 : \n");
    scanf("%d", &dim2);
    dimensions.dim1 = dim1;
    dimensions.dim2 = dim2;

    return dimensions;
}

int **createMatrix(int dim1, int dim2) {
    printf("%s", "\ncreate matrix\n");
    int **matrix = malloc(dim1 * sizeof(int *));
    for (int i = 0; i < dim1; i++) {
        matrix[i] = malloc(dim2 * sizeof(int));
    }

    for (int i = 0; i < dim1; i++) {
        for (int j = 0; j < dim2; j++) {
            printf("enter (%d,%d)\n", i, j);
            scanf("%d", &matrix[i][j]);
            printf("%d\n", matrix[i][j]);
        }
    }

    return matrix;
}

void deleteMatrix(int **matrix) {
    printf("%s", "\ndelete matrix\n");
    free(matrix); // /!\ Warning : Parameter 'matrix' may point to deallocated memory when called from function 'main'
}    

void displayMatrix(int **matrix, int dim1, int dim2) {
    if (matrix == NULL) {
        exit(1);
    }
    for (int i = 0; i < dim1; i++) {
        for (int j = 0; j < dim2; j++) {
            if (j == dim2 - 1) {
                printf("[%d]\n", matrix[i][j]);
            } else {
                printf("[%d]", matrix[i][j]);
            }
        }
    }
}

int **multiply(int **matrix1, int **matrix2, int dim11, int dim12, int dim22) {
    int **matrix3 = malloc(dim11 * sizeof(int));
    for (int i = 0; i < dim11; i++) {
        for (int j = 0; j < dim22; j++) {
            int cij = 0;
            for (int k = 0; k < dim12; k++) {
                if (matrix1 == NULL || matrix2 == NULL) {
                    exit(3);
                }
                cij += matrix1[i][k] * matrix2[k][j];
            }

            for (int l = 0; l < dim11; l++) {
                matrix3[l] = malloc(dim22 * sizeof(int));
            }
            matrix3[i][j] = cij;
            printf("cij : %d\n", matrix3[i][j]);
        }
    }
    return matrix3;
};

Here an output :

dim 1 :
2
dim 2 :
2

create matrix
enter (0,0)
1
1
enter (0,1)
0
0
enter (1,0)
0
0
enter (1,1)
1
1
[1][0]
[0][1]
dim 1 :
2
dim 2 :
2

create matrix
enter (0,0)
3
3
enter (0,1)
3
3
enter (1,0)
3
3
enter (1,1)
3
3
[3][3]
[3][3]
cij : 3
cij : 3
cij : 3
cij : 3
[-253143104][428]
[-253143104][3]

delete matrix

delete matrix

delete matrix

Process finished with exit code 0

[-253143104][428]
[-253143104][3]

Here is the wrong result. To your mind, what is the issue? Thanks a lot.

PS: if you have some ideas for improving my code, don't hesitate to tell me because I am a beginner.

PS2: as said below, I had forgotten * for int in multiply for the first malloc. But I still have the issue... after correcting.


Solution

  • There are multiple problems:

    • deleteMatrix only frees the array of row pointers. You should pass the number of rows (dim1) so it frees the individual rows that hold the matrix values.

    • displayMatrix should be simplified: you should output the newline unconditionally at the end of the inner loop.

    • enterDimensions and createMatrix should detect and report input errors and allocation failures.

    • multiplyMatrix does not allocate the result matrix properly: its rows are allocated multiple times for each resulting cell value. The net result is a massive memory leak and only the last value of each row appears correct in the final result matrix.

    Here is a modified version:

    #include <stdio.h>
    #include <stdlib.h>
    
    struct Dimensions {
        int dim1, dim2;
    };
    
    struct Dimensions enterDimensions(void);
    int **allocateMatrix(int rows, int cols);
    int **createMatrix(int rows, int cols);
    void deleteMatrix(int **mat, int rows);
    void displayMatrix(int **mat, int rows, int cols);
    int **multiply(int **mat1, int **mat2, int dim11, int dim12, int dim22);
    
    int main(void) {
        struct Dimensions dimensions1 = enterDimensions();
        int **matrix1 = createMatrix(dimensions1.dim1, dimensions1.dim2);
        printf("matrix1:\n");
        displayMatrix(matrix1, dimensions1.dim1, dimensions1.dim2);
    
        struct Dimensions dimensions2 = enterDimensions();
        int **matrix2 = createMatrix(dimensions2.dim1, dimensions2.dim2);;
        printf("matrix2:\n");
        displayMatrix(matrix2, dimensions2.dim1, dimensions2.dim2);
    
        if (dimensions1.dim2 != dimensions2.dim1) {
            printf("cannot compute the product of these matrices: dimensions do not match\n");
            deleteMatrix(matrix1, dimensions1.dim1);
            deleteMatrix(matrix2, dimensions2.dim1);
            return 1;
        } else {
            int **matrix3 = multiply(matrix1, matrix2, dimensions1.dim1, dimensions1.dim2, dimensions2.dim2);
            printf("matrix3:\n");
            displayMatrix(matrix3, dimensions1.dim1, dimensions2.dim2);
            deleteMatrix(matrix3, dimensions2.dim2);
            deleteMatrix(matrix1, dimensions1.dim1);
            deleteMatrix(matrix2, dimensions2.dim1);
            return 0;
        }
    }
    
    struct Dimensions enterDimensions(void) {
        struct Dimensions dimensions;
        printf("enter dim 1: ");
        if (scanf("%d", &dimensions.dim1) != 1) {
            printf("invalid input\n");
            exit(1);
        }
        printf("enter dim 2: ");
        if (scanf("%d", &dimensions.dim2) != 1) {
            printf("invalid input\n");
            exit(1);
        }
        return dimensions;
    }
    
    int **allocateMatrix(int dim1, int dim2) {
        if (dim1 <= 0 || dim2 <= 0) {
            printf("invalid dimensions: %d,%d\n", dim1, dim2);
            exit(1);
        }
        int **matrix = calloc(dim1, sizeof(int *));
        if (!matrix) {
            printf("allocation failed\n");
            exit(1);
        }
        for (int i = 0; i < dim1; i++) {
            matrix[i] = calloc(dim2, sizeof(int));
            if (!matrix[i]) {
                printf("allocation failed\n");
                exit(1);
            }
        }
        return matrix;
    }
    
    int **createMatrix(int dim1, int dim2) {
        int **matrix = allocateMatrix(dim1, dim2);
    
        for (int i = 0; i < dim1; i++) {
            for (int j = 0; j < dim2; j++) {
                printf("enter (%d,%d): ", i, j);
                if (scanf("%d", &matrix[i][j]) != 1) {
                    printf("invalid input\n");
                    exit(1);
                }
                //printf("%d\n", matrix[i][j]);
            }
        }
        return matrix;
    }
    
    void deleteMatrix(int **matrix, int dim1) {
        if (matrix == NULL)
            return;
        for (int i = 0; i < dim1; i++) {
            free(matrix[i]);
        }
        free(matrix);
    }
    
    void displayMatrix(int **matrix, int dim1, int dim2) {
        if (matrix == NULL)
            return;
        for (int i = 0; i < dim1; i++) {
            for (int j = 0; j < dim2; j++) {
                printf("[%d]", matrix[i][j]);
            }
            printf("\n");
        }
    }
    
    int **multiply(int **matrix1, int **matrix2, int dim11, int dim12, int dim22) {
        if (matrix1 == NULL || matrix2 == NULL)
            return NULL;
        int **matrix3 = allocateMatrix(dim11, dim22);
        for (int i = 0; i < dim11; i++) {
            for (int j = 0; j < dim22; j++) {
                int cij = 0;
                for (int k = 0; k < dim12; k++) {
                    cij += matrix1[i][k] * matrix2[k][j];
                }
                matrix3[i][j] = cij;
            }
        }
        return matrix3;
    }
    

    Note that it seems safer to store the dimensions and data into a Matrix structure. Here is a modified version using this approach:

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct Matrix {
        int dim1, dim2;
        int **data;
    } Matrix;
    
    Matrix *matrix_allocate(int rows, int cols);
    Matrix *matrix_input(void);
    void matrix_delete(Matrix *matrix);
    void matrix_display(Matrix *matrix);
    Matrix *matrix_multiply(Matrix *mat1, Matrix *mat2);
    
    int main(void) {
        Matrix *matrix1 = matrix_input();
        if (!matrix1)
            return 1;
        printf("matrix1:\n");
        matrix_display(matrix1);
    
        Matrix *matrix2 = matrix_input();
        if (!matrix2)
            return 1;
        printf("matrix2:\n");
        matrix_display(matrix2);
    
        if (matrix1->dim2 != matrix2->dim1) {
            printf("cannot compute the product of these matrices: dimensions do not match\n");
            matrix_delete(matrix1);
            matrix_delete(matrix2);
            return 1;
        } else {
            Matrix *matrix3 = matrix_multiply(matrix1, matrix2);
            if (!matrix3)
                return 1;
            printf("matrix3:\n");
            matrix_display(matrix3);
            matrix_delete(matrix3);
            matrix_delete(matrix1);
            matrix_delete(matrix2);
            return 0;
        }
    }
    
    Matrix *matrix_allocate(int dim1, int dim2) {
        if (dim1 <= 0 || dim2 <= 0) {
            printf("invalid dimensions: %d,%d\n", dim1, dim2);
            return NULL;
        }
        Matrix *matrix = calloc(1, sizeof(Matrix));
        if (!matrix)
            return NULL;
        matrix->dim1 = dim1;
        matrix->dim2 = dim2;
        matrix->data = calloc(dim1, sizeof(int *));
        if (!matrix->data) {
            printf("allocation failed\n");
            free(matrix);
            return NULL;
        }
        for (int i = 0; i < dim1; i++) {
            matrix->data[i] = calloc(dim2, sizeof(int));
            if (!matrix->data[i]) {
                printf("allocation failed\n");
                while (i-- > 0) {
                    free(matrix->data[i]);
                }
                free(matrix->data);
                free(matrix);
                return NULL;
            }
        }
        return matrix;
    }
    
    void matrix_delete(Matrix *matrix) {
        if (matrix != NULL) {
            for (int i = 0; i < matrix->dim1; i++) {
                free(matrix->data[i]);
            }
            free(matrix->data);
            free(matrix);
        }
    }
    
    Matrix *matrix_input(void) {
        int dim1, dim2;
        printf("enter dim 1: ");
        if (scanf("%d", &dim1) != 1) {
            printf("invalid input\n");
            return NULL;
        }
        printf("enter dim 2: ");
        if (scanf("%d", &dim2) != 1) {
            printf("invalid input\n");
            return NULL;
        }
        Matrix *matrix = matrix_allocate(dim1, dim2);
        if (!matrix)
            return NULL;
        for (int i = 0; i < dim1; i++) {
            for (int j = 0; j < dim2; j++) {
                printf("enter (%d,%d): ", i, j);
                if (scanf("%d", &matrix->data[i][j]) != 1) {
                    printf("invalid input\n");
                    matrix_delete(matrix);
                    return NULL;
                }
            }
        }
        return matrix;
    }
    
    void matrix_display(Matrix *matrix) {
        if (matrix == NULL)
            return;
        for (int i = 0; i < matrix->dim1; i++) {
            for (int j = 0; j < matrix->dim2; j++) {
                printf("[%d]", matrix->data[i][j]);
            }
            printf("\n");
        }
    }
    
    Matrix *matrix_multiply(Matrix *matrix1, Matrix *matrix2) {
        if (matrix1 == NULL || matrix2 == NULL || matrix1->dim2 != matrix2->dim1)
            return NULL;
        Matrix *matrix3 = matrix_allocate(matrix1->dim1, matrix2->dim2);
        if (!matrix3)
            return NULL;
        for (int i = 0; i < matrix1->dim1; i++) {
            for (int j = 0; j < matrix2->dim2; j++) {
                int cij = 0;
                for (int k = 0; k < matrix1->dim2; k++) {
                    cij += matrix1->data[i][k] * matrix2->data[k][j];
                }
                matrix3->data[i][j] = cij;
            }
        }
        return matrix3;
    }