-1

I wrote a demo on dynamic 2D arrays:

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

# define getarray2d(obj, dst) int (* dst)[obj->w] = (int (*)[obj->w])&(obj->data)

typedef struct _myarray {
    int *data;
    size_t h;
    size_t w;
} myarray;

myarray * mallocarray2d(size_t h, size_t w) {
    myarray *arr = (myarray *)malloc(sizeof(myarray));
    int *data = (int *)malloc(h * w * sizeof(int));
    arr->data = data;
    arr->h = h; arr->w = w;
}

void freearray2d(myarray *arr) {
    free(arr->data); free(arr);
}

void printarray2d(myarray *arr) {
    getarray2d(arr, array2d);
    size_t h = arr->h; size_t w = arr->w; size_t i, j;
    for (i = 0; i < h; i++) {
        for (j = 0; j < w; j++) {
            printf("%12d  ", array2d[i][j]);
        }
        printf("\n");
    }
}

int main() {
    myarray *arr = mallocarray2d(3, 4);
    printarray2d(arr);
    freearray2d(arr);
}

As expected, output is a "random" array:

F:\Users\23Xor\Desktop>a.exe
  -695987216           555             3             0
           4             0   -1651400550     268491609
  -695968000           555    -695991984           555

But things became interesting after I ran it for multiple times:

F:\Users\23Xor\Desktop>a.exe
   630939408           398     630915408           398
  2037603443    1835365491    1666986547    1697539181
  1140876664    1702259058    1952531570     977485153

F:\Users\23Xor\Desktop>a.exe
 -1688379632           607   -1688403632           607
  2037603443    1835365491    1666986547    1697539181
  1140876664    1702259058    1952531570     977485153

F:\Users\23Xor\Desktop>a.exe
  1305501456           532    1305477456           532
  2037603443    1835365491    1666986547    1697539181
  1140876664    1702259058    1952531570     977485153

F:\Users\23Xor\Desktop>a.exe
   906452752           352     906428752           352
  2037603443    1835365491    1666986547    1697539181
  1140876664    1702259058    1952531570     977485153

F:\Users\23Xor\Desktop>a.exe
 -1575002352           473   -1575026352           473
  2037603443    1835365491    1666986547    1697539181
  1140876664    1702259058    1952531570     977485153

F:\Users\23Xor\Desktop>a.exe
  1594253072           518    1594229072           518
  2037603443    1835365491    1666986547    1697539181
  1140876664    1702259058    1952531570     977485153

F:\Users\23Xor\Desktop>a.exe
   444751632           400     444727632           400
  2037603443    1835365491    1666986547    1697539181
  1140876664    1702259058    1952531570     977485153

Elements at pos (0, 1) (2, 1) (2, 3) are always equal, and elements at pos (0, 2) (0, 3) (1, 0) (1, 1) always remain 3 0 4 0

Is there a specific reason for this?

EDIT: I corrected my faults:

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

# define getarray2d(obj, dst) int (* dst)[obj->w] = (int (*)[obj->w])(obj->data)

typedef struct _myarray {
    void *data;
    size_t h;
    size_t w;
} myarray;

myarray * mallocarray2d(size_t h, size_t w) {
    myarray *arr = (myarray *)malloc(sizeof(myarray));
    void *data = malloc(h * w * sizeof(int));
    arr->data = data;
    arr->h = h; arr->w = w;
    return arr;
}

myarray * callocarray2d(size_t h, size_t w) {
    myarray *arr = (myarray *)malloc(sizeof(myarray));
    void *data = calloc(h * w, sizeof(int));
    arr->data = data;
    arr->h = h; arr->w = w;
    return arr;
}

void freearray2d(myarray *arr) {
    free(arr->data); free(arr);
}

void printarray2d(myarray *arr) {
    getarray2d(arr, array2d);
    size_t h = arr->h; size_t w = arr->w; size_t i, j;
    for (i = 0; i < h; i++) {
        for (j = 0; j < w; j++) {
            printf("%12d  ", array2d[i][j]);
        }
        printf("\n");
    }
}

int main() {
    myarray *arr = mallocarray2d(3, 4);
    printarray2d(arr);
    freearray2d(arr);
}

result:

F:\Users\23Xor\Desktop>a.exe
   630939408           398     630915408           398
  2037603443    1835365491    1666986547    1697539181
  1140876664    1702259058    1952531570     977485153

F:\Users\23Xor\Desktop>a.exe
 -1688379632           607   -1688403632           607
  2037603443    1835365491    1666986547    1697539181
  1140876664    1702259058    1952531570     977485153

F:\Users\23Xor\Desktop>a.exe
  1305501456           532    1305477456           532
  2037603443    1835365491    1666986547    1697539181
  1140876664    1702259058    1952531570     977485153

F:\Users\23Xor\Desktop>a.exe
   906452752           352     906428752           352
  2037603443    1835365491    1666986547    1697539181
  1140876664    1702259058    1952531570     977485153

F:\Users\23Xor\Desktop>a.exe
 -1575002352           473   -1575026352           473
  2037603443    1835365491    1666986547    1697539181
  1140876664    1702259058    1952531570     977485153

F:\Users\23Xor\Desktop>a.exe
  1594253072           518    1594229072           518
  2037603443    1835365491    1666986547    1697539181
  1140876664    1702259058    1952531570     977485153

F:\Users\23Xor\Desktop>a.exe
   444751632           400     444727632           400
  2037603443    1835365491    1666986547    1697539181
  1140876664    1702259058    1952531570     977485153

the last 8 elements even stops changing.

23Xor
  • 64
  • 5

1 Answers1

0

Since reading uninitialized data invokes undefined behavior, there is no satisfactory answer to your question. The official answer is: don't do that, it's not allowed by the rules of the C language, so the C language makes no guarantees about what will happen if you break the rules. You might end up reading all-zeroes, or all-42's, or 0xDEADBEEF, or your program might crash, or any other conceivable behavior might occur, because the resulting executable is not considered a valid C program.

At a practical level, you're printing out the values of whatever leftover garbage happened to be present in the area of RAM that malloc(h * w * sizeof(int)) returned to you when you called it. Why those values happened to be there (and not something different) is a function of how your C runtime's heap allocator works, combined with whatever the heap was being used for previously in your program's startup (e.g. before main() was called)... you could probably work out why they end up in that particular state, if you want to spend several days stepping through the source code of your C runtime with a debugger and a notepad. It probably wouldn't be worth the effort, though.

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • "Since reading uninitialized data invokes undefined behavior" It does not in this case. The first paragraph of your answer is all wrong. See https://stackoverflow.com/a/40674888/584518. – Lundin Nov 24 '22 at 07:55