如何使用 Haskell inline-c 查看二维数组

How to peek 2d array with Haskell inline-c

你好,我想和 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

然后在另一个函数中:

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

这总是给出段错误。

对于一维数组,我没有问题。

有人能给我提示吗?

C 二维数组实际上只是一个一维数组,在其范围内,编译器跟踪行长度以计算二维索引。如果转换为 Ptr (Ptr CDouble),此大小信息将丢失。 C 二维数组不同于数组数组的二维数组——后者通常是一个 锯齿状数组,但你也可以仅通过两次分配更有效地获得这样的数组——一个对于内容,一个是指向每一行的指针。

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;
}|]

正如您自己所记得的,C 分配的内存最终需要再次清理。 Haskell 垃圾收集器本身无法为您完成此操作,但您可以使用 ForeignPtr 而不是原始 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
   )