Alerta, porque si bien a nivel práctico no hay ninguna diferencia entre pasar un "int *array" y un "int array[12345]", si estas usando arrays multidimensionales, si que hay diferencia entre "int **array" y "int array[12345][12345]" (ya que el primero es un array de punteros a arrays de enteros, y el segundo es un array de 12345*12345 enteros). Yo personalmente te recomendaría que si estas pasando arrays de tamaño fijo, si que usases el tamaño de array el las parámetros de las funciones.
El problema viene de que estás cogiendo punteros al array. Si haces esto, entonces tendrías que declarar los argumentos como "int (*b)[2][12]" (puntero a array de 2*12 ints) y no "int *b[2][12]" (array de 2*12 punteros a ints), y otras cosas.
Pero no es necesario que lo hagas, puedes pasar directamente los arrays sin pasar un puntero a ellos. e.g. tu código quedaría:
main ()
int a[3];
int b[2][12];
funcion (a,b)
etc.
void funcion(int a[3], int b[2][12])
a[1] ++;
etc.
Fíjate como he quitado los "&" de la llamada a "funcion", los "*" de la declaración de "funcion", y el "*" en la primera línea de "funcion".