3

I'm trying to allocate a 2D char array to be accessed like ary[i][j], using this code:

#define stringmaxlen 20

void do_alloc( char ***vals, int valscount ){
    *vals = (char**) calloc( sizeof( char** ), valscount );
    int i = 0;
    for ( ; i<valscount; i++ )
        *vals[i] = (char*) calloc( sizeof( char* ), stringmaxlen );
}

int main( ){
    //......
    char** ary;
    do_alloc( &ary, 10 );
    strcpy( ary[0], "test" );
    //......
}

Unfortunately, this causes an overflow somewhere and the program have a bug in execution, I got some references from here for the dynamic allocation: http://staff.science.nus.edu.sg/~phywjs/CZ1102/lecture20/sld014.htm.

I like to know what's wrong here and how to solve the issue, thanks.

user3457200
  • 129
  • 1
  • 8
  • The parameters you use for `calloc` are in reversed order as you can see from [here](http://www.cplusplus.com/reference/cstdlib/calloc/) and [there](http://msdn.microsoft.com/en-us/library/3f8w183e.aspx); although I don't really know whether it would cause an erroneous behaviour. – Utkan Gezer Mar 24 '14 at 21:16
  • 1
    @ThoAppelsin The order of parameters to `calloc` is irrelevant on any platform that I know of. – cmaster - reinstate monica Mar 24 '14 at 21:17

2 Answers2

7

You got the operator precedence wrong: *vals[i] evaluates as *(vals[i]), not as (*vals)[i]. See http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence for details.

The fix is to change *vals[i] to (*vals)[i].

Also, the allocation *vals[i] = (char*) calloc( sizeof( char* ), stringmaxlen ); is wrong. It allocates way too much memory because it allocates space for stringmaxlen pointers, but you need only stringmaxlen characters.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
3

I want to add the following to cmaster's answer.

Instead of

*vals = (char**) calloc( sizeof( char** ), valscount );

use

*vals = (char**) calloc( sizeof( char* ), valscount );

Instead of

    (*vals)[i] = (char*) calloc( sizeof(char*), stringmaxlen );

use

    (*vals)[i] = (char*) calloc( sizeof(char), stringmaxlen );

In the first case, the size of memory allocated doesn't change since sizeof(char**) is the same as sizeof(char*). However that's not true with the second case. sizeof(char) is 1 while sizeof(char*) is larger -- 4 for 32 bit hardware, 8 for 64 bit hardware.

More importantly, it clarifies the intention -- that you would like to allocate memory for stringmaxlen characters, not stringmaxlen pointers to characters.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • 1
    You could have avoided these errors by using the idiom: `P = calloc(N, sizeof *P);`, e.g. `*vals = calloc( valscount, sizeof **vals );` etc. – M.M Mar 25 '14 at 00:35