scanf("%d %d", &a, &b);
double array1[a][b];
This is valid as of the C99 standard, although you'll want to do some sanity checking on your inputs first (i.e., make sure both inputs were actually read, make sure neither is negative, make sure they're in a reasonable range, etc.).
array1
is a variable-length array (VLA), which were first introduced in C99. They've been made optional as of C2011, but I think almost all hosted implementations still support them. To make sure, check for the __STDC_NO_VLA__
macro - if it's defined, then the implementation does not support VLAs.
size_t a, b;
if ( scanf( "%zu %zu", &a, &b ) < 2 )
// bail out with an error message
#if defined( __STDC_VERSION__ ) && __STDC_VERSION__ >= 199901L && !defined( __STDC_NO_VLA__ )
/**
* This implementation supports VLAs. We need to do an additional
* sanity check on a and b to make sure we don't allocate an
* object too large for the stack (even though VLAs
* don't have to be allocated on the stack, that's how many
* implementations choose to do it).
*/
if ( a > SOME_MAX_LIMIT || b > SOME_MAX_LIMIT )
// bail out with an error
double array1[a][b];
#else
/**
* This implementation does not support VLAs, so we'll have to use
* dynamic memory allocation. Note that memory allocated this way
* is *not* contiguous - rows are not adjacent, so the object immediately
* following array1[0][b-1] is not array1[1][0]. If that matters,
* then this won't work.
*/
double **array1 = malloc( sizeof *array1 * a );
if ( array1 )
{
size_t i;
for ( i = 0; i < a; i++ )
{
array1[i] = malloc( sizeof *array1[i] * b );
if ( !array1[i] )
break;
}
if ( i < a ) // memory allocation failure, clean up any previously allocated memory
{
while ( i-- )
free( array1[i] );
free( array1 );
// bail out with an error here
}
}
else
// memory allocation failed, bail with an error
#endif
At this point, your code can reference array1[i][j]
, no matter which way we allocated it. However, you will need to add this at the end of your function:
#if !defined( __STDC_VERSION__ ) || __STDC_VERSION__ < 199901L || defined( __STDC_NO_VLA__ )
for ( size_t i = 0; i < a; i++ )
free( array1[i] );
free( array1 );
#endif
so that we properly clean up after ourselves if we had to use malloc
.
VLAs behave pretty much like every other auto
(local) array - the memory for them will be released when you exit the function, so you can't return a pointer to them and have the pointer be valid after the function exits.
Since their size isn't determined until runtime, you can't use them at file scope (outside of any function), you can't declare them as static
, and they cannot be members of a struct
or union
type.
You can combine VLAs with dynamic memory allocation:
size_t a, b;
if ( scanf( "%zu %zu", &a, &b ) < 2 )
// bail out with an error
double (*array1)[b] = malloc( sizeof *array1 * a );
You get a dynamically-allocated 2D array with user-specified dimensions that is contiguous, and you're only limited by the heap size, not the stack size, so you can allocate large objects this way.
scanf()
) succeeded and that the values read are plausible (strictly positive and not too big) before going ahead and allocating the VLA. You should also check the other input operation too — taking appropriate action if the input fails. – Quantize