text: Q:
  
  Is it safe to use void ** when freeing double pointers of other types?
  
  I instantiated a two dimensional array in a double int pointer by the following methodology.
  int **make2Dint(int rows, int columns) {
      //a is our 2D array
      int **a = (int **)calloc(rows, sizeof(int *));
      //If we can't allocate the necessary memory, return null.
      if (!a) {
          return (int **)NULL;
      }
  
      //Allocate each row with the correct amount of column memory.
      for (int i = 0; i < rows; i++) {
          a[i] = (int *) calloc(columns, sizeof(int));
          //If we can't allocate the necessary memory, return null.
          if (!a[i]) {
              return (int **)NULL;
          }
      }
  
      return a;
  }
  
  For this, I also wrote a free function, which is as follows
  void free2DArray(void **a, int rows) {
      for (int i = 0; i < rows; i++) {
          free(a[i]);
      }
  
      free (a);
  }
  
  When going to use my free function, (by way of  free2DArray(array, rows); however, gcc gave me a warning.
  In file included from life.c:6:0:
  twoD.h:14:6: note: expected ‘void **’ but argument is of type ‘int **’
   void free2DArray(void **a, int rows);
        ^~~~~~~~~~~
  
  Now, I can make this go away with a cast to void **, but this seems to indicate that my usage of void ** is problematic.
  
  There is no generic pointer-to-pointer type in C. void * acts as a generic pointer only because conversions (if necessary) are applied automatically when other pointer types are assigned to and from void *'s; these conversions cannot be performed if an attempt is made to indirect upon a void ** value which points at a pointer type other than void *. When you make use of a void ** pointer value (for instance, when you use the * operator to access the void * value to which the void ** points), the compiler has no way of knowing whether that void * value was once converted from some other pointer type. It must assume that it is nothing more than a void *; it cannot perform any implicit conversions.
  In other words, any void ** value you play with must be the address of an actual void * value somewhere; casts like (void **)&dp, though they may shut the compiler up, are nonportable (and may not even do what you want; see also question 13.9). If the pointer that the void ** points to is not a void *, and if it has a different size or representation than a void *, then the compiler isn't going to be able to access it correctly.
  
  However, since I'm not dereferencing this pointer, I'm not sure that it's problematic. Can someone explain whether or not it's problematic, and why?
  
  A:
  
  No. Even if the pointer types have the same size and representation, C does not permit distinct types to alias except in a few special cases, and compilers can and will make transformations (optimizations) assuming this. If you really want such a generic free loop, you can put the loop in a macro that expands in the context where it has the right pointer type (in the caller) but you should really just avoid "deep" pseudo 2D arrays
  
  