p = (int *)malloc(m * n * sizeof(int));
If I use p as a two-dimensional dynamic array, how do I access the elements inside?
p = (int *)malloc(m * n * sizeof(int));
If I use p as a two-dimensional dynamic array, how do I access the elements inside?
If you can rely on your C implementation to support variable-length arrays (an optional feature), then a pretty good way would be to declare p as a pointer to (variable-length) array instead of a pointer to int:
int (*p)[n] = malloc(m * sizeof(*p));  // m rows, n columns
Then you access elements using ordinary double indexes, just as if you had declared an ordinary 2D array:
p[0][0] = 1;
p[m-1][n-1] = 42;
int q = p[2][1];
Most widely used C implementations do support VLAs, but Microsoft's is a notable exception.
 
    
    I'd personally prefer using wohlstad's method, but you could also variably-modified types, which are an optional feature of C11, but will probably be mandated in C2x:
int (*p)[m] = malloc(n * sizeof *p);
This can now be used just like a normal 2d array with automatic storage duration.
int n = 12, m = 9;
int (*p)[m] = malloc(n * sizeof *p);
for (int i = 0; i < n; ++i)
    for (int j = 0; j < m; ++j)
        p[i][j] = i * m + j;
    
printf("%d\n", p[4][2]);
free(p);
 
    
    I'll assume m is the number of columns, and n the number of rows (you can use n instead of m in my answer if it's the opposite).
In order to access the 2D array, you need 2 indices - let's call them x and y:
x index will be in the range 0 .. m-1, and
y index will be in the range 0 .. n-1
You can calculate the index for your p array in the following way:
int p_idx = y * m + x
Then you can access your arrays element e.g. this way:
p[p_idx] = 111;   // set an element value
int a = p[p_idx]; // get an element value
 
    
    You can't use p as a two-dimensional array. It's a single integer pointer. Two-dimensional (dynamically allocated) implies nested pointers. However, you can represent a two-dimensional array in a "flattened" form. Here's some code that might offer a helpful explanation:
#include <stdio.h>
#include <stdlib.h>
int main(){
    // Populating a 10x5 matrix
    int m = 10;
    int n = 5;
    int* p = (int*) malloc(m*n*sizeof(int));
    
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            // Each row has n elements; to get the
            // "flattened" index, treating the MxN
            // matrix as row-major ordered (reading
            // left-to-right, and THEN down the rows):
            int flattened_index = (i * n) + j;
            // E.g., populate with multiplication table data
            p[flattened_index] = (i + 1) * (j + 1);
            printf("%d\t", p[flattened_index]);
        }
        printf("\n");
    }
    // Inversely, to convert a flattened index to a
    // row and column, you have to use modulus
    // arithmetic
    int flattened_index = 21;
    int row = flattened_index / n; // Rounded-down integer division
    int column = flattened_index % n; // Remainder after division
    
    printf("%d * %d = %d\n", row + 1, column + 1, p[flattened_index]);
    return 0;
}
This outputs:
1   2   3   4   5   
2   4   6   8   10  
3   6   9   12  15  
4   8   12  16  20  
5   10  15  20  25  
6   12  18  24  30  
7   14  21  28  35  
8   16  24  32  40  
9   18  27  36  45  
10  20  30  40  50  
5 * 2 = 10
 
    
    You are actually creating a single-dimensional array. But still, we can use it to hold a matrix considering the fact in C a multidimensional array, e.g int mat[m][n], is stored in contiguous memory itself.
#include <iostream>
int main()
{
   int m, n;
   std::cin >> m >> n;
   int* mat_ptr = (int*)malloc(m * n * sizeof(int));
   if (mat_ptr)
   {
      for (int row = 0; row < m; ++row)
      {
        for (int col = 0; col < n; ++col)
        {
            *(mat_ptr + ((row * n) + col)) = (row * n) + col;
        }
      }
      for (int row = 0; row < m; ++row)
      {
        for (int col = 0; col < n; ++col)
        {
            std::cout << *(mat_ptr + ((row * n) + col)) << " ";
        }
        std::cout << std::endl;
      }
  }
  return 0;
}
