Reputation: 737
All
I am writing a very simple C code of dynamic 2D array declaration and initializing it with memset
and then printing out the value. My code is something as follows:
float **env;
int i,j,num;
printf("Enter a number : \n");
scanf("%d",&num);
env = (float **)malloc(num*sizeof(float *));
for(i=0;i<num;i++)
{env[i] = (float *)malloc(num*sizeof(float));}
memset(env, 0, sizeof(float)*num*num);
for(i=0;i<num;i++)
{ for (j=0;j<num;j++)
{
printf("%f\t",env[i][j]);
if (j == num -1)
{ printf("\n\n");}
}
}
for(i=0;i<num;i++)
{free(env[i]);
}
free(env);
When I compile the program, there is no compile error or warning, but when I try to print out the values I am not able to print them. Then I debugged the program, and after the memset
statement the env 2D variable is showing something like
CXX0030: Error: expression cannot be evaluated
, and when I print the values a window appears showing
Unhandled exception at 0x008b1e27 in ***.exe: 0xC0000005: Access violation reading location 0x00000000.
I have tried explicitly initializing the 2D array env to 0 using 2 for loops and it works perfectly and I am also able to print the values, but it doesn't work when I use memset
. It would be very helpful if somebody could help me out. Thank you.
Upvotes: 0
Views: 583
Reputation: 320371
Firstly, the usual advice: stop using type names under sizeof
and stop casting the result of malloc
. This is what it should've looked like
env = malloc(num * sizeof *env);
for (i = 0; i < num; i++)
env[i] = malloc(num * sizeof *env[i]);
In general, prefer to write you memory allocations by following this pattern
some_ptr = malloc(N * sizeof *some_ptr);
Secondly, the "array" you create by using this technique is not a classic C-style contiguous 2D array. Instead, you get a "simulated" 2D array assembled from a bunch of completely unrelated 1D arrays. The latter can potentially be scattered randomly in memory. This immediately means that you won't be able to process your array as a continuous object. Meanwhile your memset
call attempts to do just that. You can't do it this way. In your case you have to zero each 1D sub-array independently, using a cycle.
However, instead of allocating your 1D sub-arrays independently, you can allocate them all as a single memory block
assert(num > 0);
env = malloc(num * sizeof *env);
env[0] = malloc(num * num * sizeof *env[0]);
for (i = 1; i < num; ++i)
env[i] = env[i - 1] + num;
If allocated as shown above, you array's data will be stored in a single continuous memory block, although you still have to understand what you are doing when you are working with that array. For example, memset
ing the array data would look as follows
memset(*env, 0, num * num * sizeof **env);
or
memset(&env[0][0], 0, num * num * sizeof env[0][0]);
(which is the same thing).
Upvotes: 3
Reputation: 1132
In addition to Michael's answer, it is important to realize that float **env
will not give you a continuous chunk of memory. It will give you a pointer to a continuous chunk of memory, and in each of those memory locations is a pointer to a continuous chunk of memory, but there is no guarantee that those chunks are aligned.
For example doing:
int *x = malloc(sizeof(int));
int *y = malloc(sizeof(int));
x and y are not guaranteed to be continuous in memory, yet this is what your code is assuming.
Upvotes: 2
Reputation: 143061
Remove the memset
and use calloc
instead of malloc
, it zero-initializes allocated memory. What you're doing now is zeroing pointers you have just allocated.
Upvotes: 2