user968000
user968000

Reputation: 1843

Initializing 2d array in C using memset

I am getting an exception when printing a two-dimensional array after initializing it using memset. If I initialize each element and then access it, then there is no error. Please help to figure out the bug in the code.

#include "stdafx.h"
#include "stdlib.h"
int r = 0;
int c = 0;
int **twoDArray() {

    int *arr[5];

    for (r = 0; r < 5; r++) {

        arr[r] = (int*)malloc(2 * sizeof(int));

    }
   // 
    for (r = 0; r < 5; r++) {
        for (c = 0; c < 2; c++) {
            arr[r][c] = 1;
            printf("%d \n", arr[r][c]);
        }
    }
    memset(arr, 0, 2 * 5 * sizeof(arr[0][0]));
    for (r = 0; r < 5; r++) {
        for (c = 0; c < 2; c++) {
            printf("%d \n", arr[r][c]); //getting exception here.
        }
    }
    return arr;

}


int main()
{
    int **arr;
    arr = twoDArray();
    for (r = 0; r < 5; r++) {
        for (c = 0; c < 2; c++) {
            arr[r][c] = 0;
            printf("%d \n", arr[r][c]);
        }
    }
    return 0;
}

Upvotes: 1

Views: 1255

Answers (2)

user2736738
user2736738

Reputation: 30906

This is an array of pointers. You can be sure of two things

  • arr[0] to arr[4] is contiguous.
  • The chunk allocated is contiguous.

But who told you that the memory block allocated by each malloc which each of the pointer points to is contiguous also? Nobody did. You assumed it wrong.

In your case that's definitely not the case. That's why you invoked undefined behavior by accessing memory out of bound. (in memset).

Do this though - it would work

int (*arr)[2];
arr = malloc(sizeof *arr * 5);
// do memset - it's fine.

Don't cast the return value of malloc. It's redundant.

Something like this in earlier case:-

                                  +-------------+
        +-------+         +------>+  arr[0][0]  |
arr[0]  |       |         |       |      |    arr[0][1]
        |   +-------------+       +------+------+
        +-------+
        |       |     +------+------+
arr[1]  |    +------->+      |      |
        +-------+     |      |      |
        |       |     +-------------+              +------+------+
arr[2]  |    +-------------------------------------+      |      |
        +-------+                                  |      |      |
        |     | |                 +------+------+  +------+------+
arr[3]  |     +------------------>+      |      |
        +-------+                 |      |      |
        |       |                 +------+------+
arr[4]  |    +  |
        +-------+
             |                        +------+------+
             +----------------------->+      |      |
                                      |      |      |
                                      +------+------+

Upvotes: 3

You don't have a 2D array. You have a 1D array of pointers to 1D arrays; each of these arrays can be (and 99.9% likely is) at a different address in memory. You therefore cannot treat them as one continuous block, as memset does.

The best (and most cache-friendly) option is to allocate the entire array dynamically:

int *arr = malloc(2 * 5 * sizeof(int));

This will require you to then do manual indexing:

for (r = 0; r < 5; r++) {
    for (c = 0; c < 2; c++) {
        arr[r * 2 + c] = 1;
        printf("%d \n", arr[r * 2 + c]);
    }
}

If you know the array size at compile time (if the 2 and 5 are actual constants), you can also make arr a pointer to an actual array, to allow syntactic 2D indexing:

typedef int Array[2];

Array *arr = malloc(5 * sizeof(Array));

for (r = 0; r < 5; r++) {
    for (c = 0; c < 2; c++) {
        arr[r][c] = 1;
        printf("%d \n", arr[r][c]);
    }
}

Note that in your original code, there was also the problem you were returning a pointer into arr, which is a local variable, making the pointer immediately dangling.

Upvotes: 4

Related Questions