-6

When I run this code, I get the error in the title, here's a screenshot: (https://i.stack.imgur.com/Yevo4.jpg) And here's my code:

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

int userInput() {
    int a = 0;
    printf_s("Input your number: ");
    scanf_s("%d", &a);
    return a;
}

//allocate a 2D array
int** allocate2D(int rows, int cols)
{
    int** arr2D;
    int i;

    arr2D = (int**)malloc(rows * sizeof(int*));
    for (i = 0; i < rows; i++)
    {
        arr2D[i] = (int*)malloc(cols * sizeof(int));
    }
    return arr2D;
}
void deallocate2D(int** arr2D, int rows)
{
    int i;

    for (i = 0; i < rows; i++)
    {
        free(arr2D[i]);
    }

    free(arr2D);
}


int** array1Creator(int** array1, int row, int col) {
    srand(time(NULL));
    printf_s("first: \n");
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            array1[i][j] = rand() % 100;
            printf_s("%d ", array1[i][j]);

        }
        printf_s("\n");
    }
    return array1;
}

int** array2Creator(int** array2, int row, int col) {
    srand(time(NULL));
    printf_s("second: \n");
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            array2[i][j] = rand() % 101;
            printf_s("%d ", array2[i][j]);

        }
        printf_s("\n");
    }
    return array2;
}

void arrayMultiply(int** arr1, int** arr2, int** arr3, int c1, int r1, int c2, int r2) {
    printf_s("third: \n");
    for (int i = 0; i < r1; i++) {
        for (int j = 0; j < c2; j++) {
            arr3[i][j] = 0;
        for (int a = 0; a < c1; a++) {
                arr3[i][j] += arr1[i][a] * arr2[a][j];
            }
            printf_s("%d ", arr3[i][j]);
        }
        printf_s("\n");
    }

}


int main()
{
    int r1 = userInput();
    int c1 = userInput();
    int r2 = userInput();
    int c2 = userInput();

    int** array1 = allocate2D(r1, c1);
    int** array2 = allocate2D(r2, c2);
    int** array3 = allocate2D(r1, c1);

    if (r1 == c2) {
        arrayMultiply(array1Creator(array1, r1, c1), array2Creator(array2, r2, c2), array3, c1, r1, c2, r2);
    }
    else
        printf_s("wrong values of rows or columns");


    deallocate2D(array1, r1);
    deallocate2D(array2, r2);
    deallocate2D(array3, r1);

    return 0;
}

I have an HEAP CORRUPTION DETECTED error in VS debugger, probably in the block with memory deallocation (deallocate2D(array3, r1);) at the end of the code, but changing the rows of the matrix does not change anything. Сan anyone tell me how to fix this error?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
grzegorz1
  • 1
  • 1
  • In the expression `arr2[a][j]`, what happens if `c1 > r2`? And what happens with `arr3` if `r1 > r3` or `c1 > c3`? – Some programmer dude Dec 17 '22 at 09:16
  • @Someprogrammerdude I don't have r3 and c3 in my code – grzegorz1 Dec 17 '22 at 09:23
  • Oh right, for that I'm sorry. But you still have the problem with `c1 > c2` for `arr2`. I recommend you use [common debugging techniques](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) to check the indexes you use for `arr2` in your `arrayMultiply` function. – Some programmer dude Dec 17 '22 at 09:26
  • 3
    Is your code meant to be C++ (as hinted by `#include `) or is it meant to be C code (as hinted by everything else)? Choose one tag, not both. They are different languages. – Jonathan Leffler Dec 17 '22 at 09:28
  • See also [`srand()` — why call it only once?](https://stackoverflow.com/q/7343833/15168) – Jonathan Leffler Dec 17 '22 at 09:29
  • 1
    You aren't allocating the correct space for `array3`. If you multiply an NxM matrix by a PxQ matrix, then M must equal P and the result is an NxQ matrix, is it not? – Jonathan Leffler Dec 17 '22 at 09:36
  • And I think your test for multipliability is wrong. You should be checking that `c1 == r2` if you are multiplying `array1` by `array2`. It would be perverse to pass `array1` as the first argument and `array2` as the second argument and then multiply `array2` by `array1`. Of course, if they're square matrices, there won't be a problem, but that's an accident rather than deliberate. It would help if you told us what values you enter for the array dimensions — that's a part of creating an [MCVE]. – Jonathan Leffler Dec 17 '22 at 09:45

1 Answers1

0

As I noted in comments:

  1. srand() — why call it only once?
  2. You aren't allocating the correct space for array3. If you multiply an NxM matrix by a PxQ matrix, then M must equal P and the result is an NxQ matrix.
  3. Your test for whether the two matrices can be multiplied is wrong. You should be checking that c1 == r2 if you are multiplying array1 by array2. It would be perverse to pass array1 as the first argument and array2 as the second argument and then multiply array2 by array1. Of course, if they're square matrices, there won't be a problem, but that's an accident rather than deliberate.

Here is a fairly minimal upgrade to your code that fixes those problems. It separates the array printing from the initialization and multiplication functions. Mixing I/O and arithmetic is rarely a good idea. It also checks the memory allocations — which is always necessary. And it checks the inputs — which is also always necessary.

/* SO 7483-2964 */
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

static void err_exit(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    exit(EXIT_FAILURE);
}

static int userInput(void)
{
    int a;
    printf("Input your number: ");
    if (scanf("%d", &a) != 1)
    {
        fprintf(stderr, "Failed to read input number\n");
        exit(EXIT_FAILURE);
    }
    return a;
}

// allocate a 2D array
static int **allocate2D(int rows, int cols)
{
    int **arr2D = (int **)malloc(rows * sizeof(int *));
    if (arr2D == NULL)
        err_exit("failed to allocate %zu bytes of memory\n", rows * sizeof(int *));
    for (int i = 0; i < rows; i++)
    {
        arr2D[i] = (int *)malloc(cols * sizeof(int));
        if (arr2D[i] == NULL)
            err_exit("failed to allocate %zu bytes of memory\n", cols * sizeof(int));
    }
    return arr2D;
}

static void deallocate2D(int **arr2D, int rows)
{
    for (int i = 0; i < rows; i++)
        free(arr2D[i]);
    free(arr2D);
}

static void arrayPrint(const char *tag, int wid, int **arr, int rows, int cols)
{
    printf("%s (%dx%d):\n", tag, rows, cols);
    for (int i = 0; i < rows; i++)
    {
        const char *pad = "";
        for (int j = 0; j < cols; j++)
        {
            printf("%s%*d", pad, wid, arr[i][j]);
            pad = " ";
        }
        putchar('\n');
    }
}

static void arrayInitialize(int **array1, int row, int col)
{
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
            array1[i][j] = rand() % 100;
    }
}

static void arrayMultiply(int **arr1, int **arr2, int **arr3, int r1, int c1, int r2, int c2)
{
    assert(c1 == r2);
    for (int i = 0; i < r1; i++)
    {
        for (int j = 0; j < c2; j++)
        {
            int sum = 0;
            for (int a = 0; a < c1; a++)
                sum += arr1[i][a] * arr2[a][j];
            arr3[i][j] = sum;
        }
    }
}

enum { MAX_ROWS = 16, MAX_COLS = 16 };

int main(void)
{
    int r1 = userInput();
    int c1 = userInput();
    if (r1 <= 0 || r1 > MAX_ROWS || c1 <= 0 || c1 > MAX_COLS)
        fprintf(stderr, "Invalid dimensions (%d, %d) for array1\n", r1, c1);

    int r2 = userInput();
    int c2 = userInput();
    if (r2 <= 0 || r2 > MAX_ROWS || c2 <= 0 || c2 > MAX_COLS)
        fprintf(stderr, "Invalid dimensions (%d, %d) for array2\n", r2, c2);

    putchar('\n');
    srand(time(NULL));

    int **array1 = allocate2D(r1, c1);
    int **array2 = allocate2D(r2, c2);
    int **array3 = allocate2D(r1, c2);

    if (c1 == r2)
    {
        arrayInitialize(array1, r1, c1);
        arrayPrint("array1", 3, array1, r1, c1);
        arrayInitialize(array2, r2, c2);
        arrayPrint("array2", 3, array2, r2, c2);
        arrayMultiply(array1, array2, array3, r1, c1, r2, c2);
        arrayPrint("array3", 6, array3, r1, c2);
    }
    else
        fprintf(stderr, "wrong values of rows or columns (%d, %d) vs (%d, %d): %d != %d\n",
                r1, c1, r2, c2, c1, r2);

    deallocate2D(array1, r1);
    deallocate2D(array2, r2);
    deallocate2D(array3, r1);

    return 0;
}

Example run:

Input your number: 3
Input your number: 5
Input your number: 5
Input your number: 4

array1 (3x5):
 62   5  74  71  53
 97  34  47  23  33
 51  85  62  43  57
array2 (5x4):
 29  60   1  54
 38  36  92  76
 22  99  68  44
 23  25  74   6
 13  51  27  68
array3 (3x4):
  5938  15704  12239  11014
  6097  13955   9014  12272
  7803  16240  16808  16076

Since the arrays are quite small (the revised code only allows arrays up to 16x16, so each array is a maximum of 1 KiB on a system where sizeof(int) == 4, there is no particular need to use dynamic memory allocation even for VLAs (variable-length arrays). Using VLAs in the called functions makes for very easy notations. Here is a version that uses direct memory allocation:

/* SO 7483-2964 */
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

static void err_exit(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    exit(EXIT_FAILURE);
}

static int userInput(void)
{
    int a;
    printf("Input your number: ");
    if (scanf("%d", &a) != 1)
        err_exit("Failed to read input number\n");
    return a;
}

static void arrayPrint(const char *tag, int wid, int rows, int cols, int arr[rows][cols])
{
    printf("%s (%dx%d):\n", tag, rows, cols);
    for (int i = 0; i < rows; i++)
    {
        const char *pad = "";
        for (int j = 0; j < cols; j++)
        {
            printf("%s%*d", pad, wid, arr[i][j]);
            pad = " ";
        }
        putchar('\n');
    }
}

static void arrayInitialize(int row, int col, int arr[row][col])
{
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
            arr[i][j] = rand() % 100;
    }
}

static void arrayMultiply(int r1, int c1, int arr1[r1][c1],
                          int r2, int c2, int arr2[r2][c2], int arr3[r1][c2])
{
    assert(c1 == r2);
    for (int i = 0; i < r1; i++)
    {
        for (int j = 0; j < c2; j++)
        {
            int sum = 0;
            for (int a = 0; a < c1; a++)
                sum += arr1[i][a] * arr2[a][j];
            arr3[i][j] = sum;
        }
    }
}

enum { MAX_ROWS = 16, MAX_COLS = 16 };

int main(void)
{
    int r1 = userInput();
    int c1 = userInput();
    if (r1 <= 0 || r1 > MAX_ROWS || c1 <= 0 || c1 > MAX_COLS)
        err_exit("Invalid dimensions (%d, %d) for array1\n", r1, c1);

    int r2 = userInput();
    int c2 = userInput();
    if (r2 <= 0 || r2 > MAX_ROWS || c2 <= 0 || c2 > MAX_COLS)
        err_exit("Invalid dimensions (%d, %d) for array2\n", r2, c2);
    if (c1 != r2)
        err_exit("wrong values of rows or columns (%d, %d) vs (%d, %d): %d != %d\n",
                r1, c1, r2, c2, c1, r2);

    putchar('\n');
    srand(time(NULL));

    int array1[r1][c1];
    int array2[r2][c2];
    int array3[r1][c2];

    arrayInitialize(r1, c1, array1);
    arrayPrint("array1", 3, r1, c1, array1);
    arrayInitialize(r2, c2, array2);
    arrayPrint("array2", 3, r2, c2, array2);
    arrayMultiply(r1, c1, array1, r2, c2, array2, array3);
    arrayPrint("array3", 6, r1, c2, array3);

    return 0;
}

And if you are worried about VLAs breaking the stack limit, here's a variant that uses dynamic memory allocation for the arrays. The called functions haven't changed, but the allocation for the arrays and the function calls have changed.

/* SO 7483-2964 */
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

static void err_exit(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    exit(EXIT_FAILURE);
}

static int userInput(void)
{
    int a;
    printf("Input your number: ");
    if (scanf("%d", &a) != 1)
        err_exit("Failed to read input number\n");
    return a;
}

static void arrayPrint(const char *tag, int wid, int rows, int cols, int arr[rows][cols])
{
    printf("%s (%dx%d):\n", tag, rows, cols);
    for (int i = 0; i < rows; i++)
    {
        const char *pad = "";
        for (int j = 0; j < cols; j++)
        {
            printf("%s%*d", pad, wid, arr[i][j]);
            pad = " ";
        }
        putchar('\n');
    }
}

static void arrayInitialize(int row, int col, int arr[row][col])
{
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
            arr[i][j] = rand() % 100;
    }
}

static void arrayMultiply(int r1, int c1, int arr1[r1][c1],
                          int r2, int c2, int arr2[r2][c2], int arr3[r1][c2])
{
    assert(c1 == r2);
    for (int i = 0; i < r1; i++)
    {
        for (int j = 0; j < c2; j++)
        {
            int sum = 0;
            for (int a = 0; a < c1; a++)
                sum += arr1[i][a] * arr2[a][j];
            arr3[i][j] = sum;
        }
    }
}

enum { MAX_ROWS = 16, MAX_COLS = 16 };

int main(void)
{
    int r1 = userInput();
    int c1 = userInput();
    if (r1 <= 0 || r1 > MAX_ROWS || c1 <= 0 || c1 > MAX_COLS)
        err_exit("Invalid dimensions (%d, %d) for array1\n", r1, c1);

    int r2 = userInput();
    int c2 = userInput();
    if (r2 <= 0 || r2 > MAX_ROWS || c2 <= 0 || c2 > MAX_COLS)
        err_exit("Invalid dimensions (%d, %d) for array2\n", r2, c2);
    if (c1 != r2)
        err_exit("wrong values of rows or columns (%d, %d) vs (%d, %d): %d != %d\n",
                r1, c1, r2, c2, c1, r2);

    putchar('\n');
    srand(time(NULL));

    int (*array1)[r1][c1] = malloc(r1 * c1 * sizeof((*array1)[0][0]));
    if (*array1 == NULL)
        err_exit("failed to allocate %zu bytes of memory\n", (r1 * c1 * sizeof((*array1)[0][0])));
    int (*array2)[r2][c2] = malloc(r2 * c2 * sizeof((*array1)[0][0]));
    if (*array2 == NULL)
        err_exit("failed to allocate %zu bytes of memory\n", (r2 * c2 * sizeof((*array2)[0][0])));
    int (*array3)[r1][c2] = malloc(r1 * c2 * sizeof((*array1)[0][0]));
    if (*array3 == NULL)
        err_exit("failed to allocate %zu bytes of memory\n", (r1 * c2 * sizeof((*array3)[0][0])));

    arrayInitialize(r1, c1, *array1);
    arrayPrint("array1", 3, r1, c1, *array1);
    arrayInitialize(r2, c2, *array2);
    arrayPrint("array2", 3, r2, c2, *array2);
    arrayMultiply(r1, c1, *array1, r2, c2, *array2, *array3);
    arrayPrint("array3", 6, r1, c2, *array3);

    free(*array1);
    free(*array2);
    free(*array3);

    return 0;
}

If run from a script with the same inputs and during the same second, then the three programs produce the same result. That's a deficiency in using time() as the seed for srand() — but it is also convenient for testing.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278