Как передать массив в функцию С++ ( пишет no matching function to call)?
Используя Кресты, стоит использовать и их удобства.
std::vector< std::vector< int > > a(rowCount, std::vector< int >(colCount, 0));
void average (std::vector< std::vector< int > > &a){
Так вы не нарветесь на промахи в индексах массива, например. Если умеючи.

А в вашем коде int[][], конечно, не может самопроизвольно превратиться в int*
Написал опус на вопрос, который вы удалили, хорошо сохранился в буфере обмена :-) а то было бы обидно.

Ваш массив пожно просто привести к указателю, по старинке (int*)a или используя касты.

Но у вас тут на самом деле 2 проблемы.
Первая - обращение к элементам массива в average используя [i][j]. Вторая - VLA.
По первой проблеме:
В С/С++ оператор индексации (array[i]) выполняет следующее действие: *(array+i).
Отсюда должно быть понятно, что раз array у вас это int*, то после array[i] вы получите int, от которого уже нельзя взять второй индекс, т.к. это просто 1 int, а не массив.

Отсюда есть несколько выходов:
1. дурацкий (самый долгий по исполнению и затратам памяти): использовать динамический массив массивов
Выглядит примерно так:
int **array = new int*[rowCount];
for(int i=0; i < rowCount; ++i)
   array[i] = new int[colCount];
Как видите array превратился в двойной указатель, теперь каждый элемент в первом измерении - это указатель на одномерный массив. Всего у вас получается rowCount + 1 выделений памяти. Не забудьте столько же раз вызвать оператор delete.
В average теперь передавайте  int** и у вас будет работать оператор [][], т.к. первая индексация уже будет возвращать int*.
Не рекомендую использовать этотт способ.

2. Вычислять индекс массива вручную (не использовать индексацию):
*(array + i*colCount + j)
Это такой хардкорный стиль. Но зато работает быстро и масштабируется на массивы любой размерности без особых проблем.

3. использовать std::vector<std::vector<int>> - это то же самое, что и вариант 1, но закамуфлированный под вектор :-)

Вторая проблема это VLA (Variable Length Array).
Статические (автоматические) массивы в С++ вы можете определять, только константным размером (размером известным на этапе компиляции).
У вас же размерность массива динамическая (вводится пользователем во время выполнения программы). Отсюда следует, что вы должны использовать динамические массивы, выделенные с помощью new.
В стандарте С++ нет VLA. VLA есть только в Си и то начиная с С99.
Ваша функция task3 компилируется, только потому что в gcc/clang по умолчанию включены расширения. В расширения входит так же и возможность использовать VLA. Если задать опциями более строгое соответствие стандарту С++, то функция не соберется.
И кстати, например в микросовтовский компилятор VLA до сих пор не завезли.

Но если уж у вас есть  VLA, то вы можете преобразовывать указатель в VLA массив с помощью такой кучерявой конструкции:
int (*array2)[colCount] = (int(*)[colCount]) array;
В этом случае обращаться к элементам массива можно как обычно через двойную индексацию: array2[i][j]
Когда-то делал тест на эту тему: https://ideone.com/4i6lRw
Кстати, если в average сначала передать размерности, и последним параметром массив, то по идее массив можно сразу объявить двумерным, используя ранее переданные размерности:
void average(int rowcount, int colcount, int aarray[rowCount][colCount])
Это то же VLA.

Вообще не рекомендую в С++ использовать VLA, т.к. программа становится не переносимой и зависимой от компилятора.