Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a conversion from a pointer to type to a pointer to array of type safe?

A few days ago I stumbled on a code where an extensive use of conversions from pointer to type to pointer to array of type was made to give a bi-dimensional view of a linear vector in memory. A simple example of such a technique is reported below for clarity:

#include <stdio.h>
#include <stdlib.h>

void print_matrix(const unsigned int nrows, const unsigned int ncols, double (*A)[ncols]) {  
  // Here I can access memory using A[ii][jj]
  // instead of A[ii*ncols + jj]
  for(int ii = 0; ii < nrows; ii++) {
    for(int jj = 0; jj < ncols; jj++)
      printf("%4.4g",A[ii][jj]);
    printf("\n");
  }
}

int main() {

  const unsigned int nrows = 10;
  const unsigned int ncols = 20;

  // Here I allocate a portion of memory to which I could access
  // using linear indexing, i.e. A[ii]
  double * A = NULL;
  A = malloc(sizeof(double)*nrows*ncols);

  for (int ii = 0; ii < ncols*nrows; ii++)
    A[ii] = ii;

  print_matrix(nrows,ncols,A);
  printf("\n");
  print_matrix(ncols,nrows,A);

  free(A);
  return 0;
}

Given that a pointer to type is not compatible with a pointer to array of type, I would like to ask if there are risks associated with this casting, or if I can assume that this casting will work as intended on any platform.

like image 747
Massimiliano Avatar asked Oct 12 '12 14:10

Massimiliano


1 Answers

UPDATE: the strikethrough part is true, but irrelevant.

As I posted in the comment, the question is really whether in a two-dimensional array, the subarrays (rows) contain internal padding. There shall certainly be no padding inside each row, as the standard defines arrays to be contiguous. Also, the outer array shall introduce no padding. In fact, scanning through the C standard, I find no mention of padding in the context of arrays, so I interpret "contiguous" to mean that there's never any padding at the end of a subarray inside a multidimensional array. Since sizeof(array) / sizeof(array[0]) is guaranteed to return the number of elements in an array, there can be no such padding.

That means that the layout of a multidimensional array of nrows rows and ncols columns must be the same as that of an 1-d array of nrows * ncols. So, to avoid the incompatible type error, you could do

void *A = malloc(sizeof(double[nrows][ncols]));
// check for NULL

double *T = A;
for (size_t i=0; i<nrows*ncols; i++)
     T[i] = 0;

then pass to print_array. This should avoid the potential pitfall of pointer aliasing; pointers of different types are not permitted to point into the same array unless at least one of them has type void*, char* or unsigned char*.

like image 127
Fred Foo Avatar answered Oct 16 '22 05:10

Fred Foo