In this code snippet
char** p; int i; p=(char**)malloc(10*sizeof(char*)); for(i=0;i<10;i++) p[i]=(char*)malloc(10*sizeof(char));
memory is allocated for a one-dimensional array of 10 char * pointers:
p=(char**)malloc(10*sizeof(char*));
Each pointer, in turn, is initialized with the allocated memory address for a one-dimensional array of 10 elements of type char :
for(i=0;i<10;i++) p[i]=(char*)malloc(10*sizeof(char));
In this fragment of the fragment
char** p; int i; p=(char**)malloc(10*sizeof(char*)); *p=(char*)malloc(100*sizeof(char)); for(i=1;i<10;i++) p[i]=p[0]+10*i;
first, memory is allocated for a one-dimensional array of 10 elements of type char * , as in the first code fragment.
p=(char**)malloc(10*sizeof(char*));
However, then only the first element of the array is initialized with the address of the allocated memory for the bulk array of 100 elements of type char .
*p=(char*)malloc(100*sizeof(char));
The above statement is equivalent
p[0]=(char*)malloc(100*sizeof(char));
And then the other 9 pointers are initialized with integer expressions 10*i
for(i=1;i<10;i++) p[i]=p[0]+10*i;
Obviously, this does not make sense. The values of these 9 elements are invalid because they are not pointers to objects. This is the purpose of these initializations is unclear.
Note that you can allocate memory for one two-dimensional array as follows:
char ( *p )[10] = malloc( 100 * sizeof( char ) );
The advantage of this allocation is that you only need one call to the free function to free up all the allocated memory. And, in addition, this pointer can be used as an argument for a function that has a parameter in the form of two two-dimensional arrays.
for instance
void func( char a[][10] );
You can call this function, for example
func( p );
However, you cannot call a function if p is of type char ** , because this type is incompatible with the type of the parameter.