By definition of the []
subscript operator, the expression
a[b]
is equivalent to:
*(a+b)
This means that the expression
m[3][3]
is equivalent to:
*( (*(m+3)) + 3 )
Since you defined m
to be a pointer to a pointer to an int
, the expression m[3][3]
will do the following: It will treat m
as if it were a pointer to the first element of an array whose elements are of type int *
. It will attempt to read the fourth element of this array. It will treat this fourth element as a pointer to the first element of an array whose elements are of type int
and it will attempt to read the fourth element of this array.
However, m[3]
has an indeterminate ("garbage") value, so m[3]
does not point to a valid array. Therefore, by dereferencing this invalid pointer in the expresson m[3][3]
, your program is invoking undefined behavior, which means that anything can happen, including the behavior that you described in the question.
Because you used the line
m=(int **)malloc(10*10*sizeof(int));
I assume that it was not your intent to make m
point to the first element of an array whose elements are of type int *
, but rather to make m
point to a 2D array of int
elements. In other words, m
should point to the first element of an array whose elements are not pointers, but arrays.
In order to accomplish this, you must declare the variable m
differently.
The line
int **m;
will declare the variable m
to be a pointer to a pointer to an int
. This is not what you want. You want it to point to the first sub-array of the 2D array, so you want to declare a pointer to an array of 10 int
elements. For this, you must use the following syntax:
int (*m)[10];
The parentheses are important, because without them, you would be declaring an array of 10 elements of type int *
, but you want to instead declare a pointer to an array of 10 int
elements.
Your program should look like this:
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
int (*m)[10];
m = malloc( 10*10*sizeof(int) );
if ( m == NULL )
{
fprintf( stderr, "Memory allocation failure!\n" );
exit( EXIT_FAILURE );
}
m[3][3]=3;
printf( "%d", m[3][3] );
free( m );
}
This program has the following output:
3
Note that in C, in constrast to C++, it is not necessary and generally discouraged to cast the result of malloc
.
Also, it is generally a good idea to check the return value of malloc
, to verify that the memory was successfully allocated. Additionally, you should generally free
the memory when you no longer need it.