Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why am I getting junk values despite using calloc()?

I would like to know why the first two elements are always non-zero. I don't know how more I can describe the question, but this is not allowing me to post the question, so I'm writing this. Not sure if this will work.

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

#define SIZE 3

void printMatrix(int **m)
{
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++)
            printf("%d ", m[i][j]);
        printf("\n");
    }
}

int main(int argc, char const *argv[])
{
    int **matrix;

    matrix = (int **) calloc(sizeof(int), SIZE);

    for (int i = 0; i < SIZE; ++i)
        matrix[i] = (int *) calloc(sizeof(int), SIZE);

    printf("%s\n", "Matrix initialized.");

    printMatrix(matrix);

    return 0;
}

Output:

Matrix initialized.
1371548192 32653 0 
0 0 0 
0 0 0
like image 805
Nikhil CSB Avatar asked Jan 01 '23 15:01

Nikhil CSB


2 Answers

You're not allocating enough memory:

matrix = (int **) calloc(sizeof(int), SIZE);

Here you're attempting to create an array of 3 int *, but you're only allocating space for 3 int. If a pointer is larger than an int on your system, which it most likely is, you write past the end of the array when you create the arrays for each row. Writing past the end of allocated memory invokes undefined behavior.

Since you're creating an array of int *, use that for the size of each element:

matrix = calloc(sizeof(int *), SIZE);

Also, don't cast the return value of malloc/realloc/calloc, as that can mask a bug if you forget to #include <stdlib.h>

like image 170
dbush Avatar answered Jan 09 '23 12:01

dbush


The code uses calloc(sizeof(int), SIZE), but the actual datatype in the structure is int *, leading to insufficient memory allocation on some systems (mine gives int size as 4 and int * size as 8).

Here's a rewrite suggestion (we'll swap size parameters in the calloc call per its header):

int main(int argc, char const *argv[]) {
    int **matrix;

    if (!(matrix = calloc(SIZE, sizeof(*matrix)))) { 
        fprintf(stderr, "calloc failed");
        return 1;
    }

    for (int i = 0; i < SIZE; ++i) {
         if (!(matrix[i] = calloc(SIZE, sizeof(*(matrix[i]))))) {
            fprintf(stderr, "calloc failed");
            return 1;
        }
    }

    printf("%s\n", "Matrix initialized.");
    printMatrix(matrix);
    return 0;
}

Here, we use *matrix and *matrix[i] instead of hard coding the types int * and int respectively. This can help us avoid bugs and hunting for locations to change code if we need to make type adjustments at some point.

We also check that calloc succeeds by testing that the pointer is non-NULL. Failing to do so can introduce difficult-to-find bugs due to undefined behavior.

Note Do I cast the result of malloc?.

like image 39
ggorlen Avatar answered Jan 09 '23 13:01

ggorlen