[variable length arrays](https://en.wikipedia.org/wiki/Variable-length_array) are required in C99 and optional in C11, C17/18. To detect, something like #if defined(__STDC__) && defined(__STDC_VERSION__) && \ (__STDC_VERSION__ == 199901 || (__STDC_VERSION__ >= 201112 && __STDC_NO_VLA__ != 1)) #define VLA_OK 1 #else #define VLA_OK 0 #ednif If code does not use a variable length arrays, code could take advantage that the address of the first element of the 2D array is _equivalent_ to `&arr[0][0]` and that 2D arrays are continuous. void fill(void *arr, size_t rows, size_t cols, int val) { int *a = arr; for(size_t i = 0; i < rows; i++) { for(size_t j = 0; j < cols; j++) { *a++ = val; } } } Sample usage #define IN 5 #define JN 3 int arr[IN][JN]; fill(arr, IN, JN, 0x45); This does lose type checking. Code instead could oblige passing the address of the first `int` // v---v---- type checked void fill(int *arr, size_t rows, size_t cols, int val) { for(size_t i = 0; i < rows; i++) { for(size_t j = 0; j < cols; j++) { *arr++ = val; } } } Sample usage #define IN 5 #define JN 3 int arr[IN][JN]; fill(&arr[0][0], IN, JN, 0x45); // or fill(arr[0], IN, JN, 0x45);