Reputation: 1843
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
Reputation: 30906
This is an array of pointers. You can be sure of two things
arr[0]
to arr[4]
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
Reputation: 171097
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