Home > Back-end >  How to peek 2d array with Haskell inline-c
How to peek 2d array with Haskell inline-c

Time:11-05

Hello I'd like to work with 2d arrays:

--2d arrays
cArray :: IO (Ptr (Ptr CDouble))
cArray = do
  x <- [C.block| double (*)[2] {

  double (*ptd)[2] = malloc(sizeof(double[2][2]));
  ptd[0][0] = 1.78;
  ptd[0][1] = 1.68;
  ptd[1][0] = 1.58;
  ptd[1][1] = 1.48;
  printf("the firstelement is: %f\n", ptd[1][1]);
  return ptd;
}|]
  
  return x

Then in another function:

  e <- cArray :: IO (Ptr (Ptr CDouble))
  e1 <- peekElemOff e 0 :: IO (Ptr CDouble)  
  e2 <- peekElemOff e1 0 :: IO CDouble
  print e2

This always gives segment fault.

For 1-d array, i don't have problems.

Could anyone give me a hint?

CodePudding user response:

A C 2D array is really just a 1D array where, within its scope, the compiler keeps track of the row length to compute the 2D indexing. This size information would be lost if you transform to Ptr (Ptr CDouble). A C 2D array is distinct from an array-of-arrays 2D array – which would in general be a jagged array, but you can also obtain such an array more efficiently with only two allocations – one for the content, one for the pointers to each row.

cArray :: IO (Ptr (Ptr CDouble))
cArray = [C.block| double** {

  int n = 2, m = 2;
  double* arr = malloc(sizeof(double[n*m]));
  double** ptd = malloc(sizeof(double*[n]));
  for (int i=0; i<2;   i)
    ptd[i] = &(arr[i*m]);
  ptd[0][0] = 1.78;
  ptd[0][1] = 1.68;
  ptd[1][0] = 1.58;
  ptd[1][1] = 1.48;
  printf("the firstelement is: %f\n", ptd[0][0]);
  return ptd;
}|]

As you've remembered yourself, C-allocated memory eventually needs to be cleaned up again. The Haskell garbage collector can't do this for you my itself, but you can hook into it by using a ForeignPtr instead of a raw Ptr.

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes     #-}

import Language.C.Inline as C
import Foreign.Ptr
import Foreign.ForeignPtr
import Foreign.Storable

C.include "<stdio.h>"
C.include "<stdlib.h>"

cArray :: IO (ForeignPtr (Ptr CDouble))
cArray = do
 x <- [C.block| double** {
   int n = 2, m = 2;
   double* arr = malloc(sizeof(double[n*m]));
   double** ptd = malloc(sizeof(double*[n]));
   for (int i=0; i<2;   i)
     ptd[i] = &(arr[i*m]);
   ptd[0][0] = 1.78;
   ptd[0][1] = 1.68;
   ptd[1][0] = 1.58;
   ptd[1][1] = 1.48;
   printf("the firstelement is: %f\n", ptd[0][0]);
   return ptd;
  }|]
 let finalizer = [C.funPtr| void free2Darray(double** ptd) {
   free(ptd[0]);
   free(ptd);
  }|]
 newForeignPtr finalizer x


main = do
  cArray >>= (`withForeignPtr` \e -> do
    e1 <- peekElemOff e 0
    e2 <- peekElemOff e1 0
    print e2
   )
  • Related