Для того чтобы создать двумерный динамический массив на си необходимо выделить память под один одномерный массив, элементами которого будут также являться одномерные массивы. Пусть наш массив будет называться А и хранить в себе целочисленные значения. Для начала необходимо вспомнить, что имя массива содержит в себе ссылку на первый элемент, поэтому мы будем использовать указатель (*). Так как массив A будет двумерным, то он будет указывать на элемент, который также будет являться массивом. То есть для него также потребуется указатель, тогда его объявление будет выглядеть следующим образом: int** a, то есть указатель, на указатель на int. Выделим для него память. Так как каждый элемент будет являться массивом, количество которых определим как AN, то выделение памяти будет выглядеть так: malloc(an * sizeof(int*)), где malloc - выделение памяти, количество которой определяется значением его аргумента. В данном случае это количество внутренних массивов (AN) помноженное на размер одного указателя на целочисленный тип данных sizeof(int*). Напомню, что мы создали переменную A с типом указателя на указатель на int (int**), поэтому нам нужно привет полученное значение от функции malloc к этому типу. Для этого воспользуемся приведением, которое выглядит следующим образом: (int**). Тогда первая строчка будет выглядеть так: int** a = (int**)malloc(an * sizeof(int*)). Далее нам необходимо пройтись по всем внутренним массивам и выделить для них память. Размер памяти будет исчисляться стандартным int, так как именно значения этого типа данных мы будем хранить. Для того, чтобы пройтись по всему массиву, размерность которого нам известна, воспользуемся циклом for. Напомню, что обращение к элементу массива происходит через индекс, заключенный в квадратные скобки, тогда каждому a[i] мы присвоим значение (int*)malloc(am * sizeof(int)), где AM - это количество элементов во внутреннем массиве. Тогда финальный вариант будет выглядеть следующим образом:
int** a = (int**)malloc(an * sizeof(int*));
for (int i = 0; i < an; i++)
a[i] = (int*)malloc(am * sizeof(int));