【问题标题】:R Using function Realoc with .C interfaceR使用带有.C接口的函数Realoc
【发布时间】:2014-05-23 03:21:19
【问题描述】:

我正在使用 .C 接口测试从 R 对 C 函数的调用。测试包括将一个数字向量传递给没有条目的 C 函数,动态分配 n 个位置,进行归因并将向量返回给 R。

我正在使用 R.h. 的 Calloc。该函数的原型是

type* Calloc(size_t n, type)

如编写 R 扩展中所述。

问题是我没有得到带有 R 中分配位置的新向量。向量仍然没有条目。

R中的代码

fooR <- function(x) {
  if (!is.numeric(x))
    stop("argument x must be numeric")
  out <- .C("foo",
            x=as.double(x))
  return(out$x)
}

x <- numeric()

result <- fooR(x)

C语言中的函数

#include <R.h>

void foo(double *x)
{
  int i, n;

  n = 4;
  x = Calloc(n, double);

  for (i = 0; i < n; i++) {
    x[i] = i;
    printf("%f\n", x[i]); //just to check
  }
}

问题是:.C 接口可以处理这样的内存分配吗?

【问题讨论】:

    标签: c r memory-management vector dynamic-allocation


    【解决方案1】:

    是的,您可以通过这种方式使用内存管理,但前提是您使用.Call() 接口而不是.C() 接口。

    请参阅 Memory AllocationInterface Functions 的“编写 R 扩展”手册。

    还有其他书籍和一些例子。我更喜欢 C++ 而不是 C,并且使用 Rcpp 我们可以隐藏所有机制:

     R> cppFunction('IntegerVector makeVec(int n) { return IntegerVector(n); }')
     R> makeVec(2)
     [1] 0 0
     R> makeVec(4)
     [1] 0 0 0 0
     R> 
    

    这在后台同时使用了.Call() 和 R 的内存分配,这是一个快速的小证明,证明“是的,你可以”实际上动态地创建了一个向量。

    【讨论】:

    • 如果为真,请告诉我如何更改在foo 外部“可见”的x 地址? (签名为foovoid foo(double *x)
    • 请阅读.Call()——它接受并返回SEXP对象。因此,我们无法使用 R 提供给我们的界面来容纳您所需的签名。
    • 如何使用 Realloc() 而不是 Calloc()。我的意思是你通过 .C()、Realloc() 发送一个包含 n 个元素的数组 x(例如双精度数)从 R 到 C,例如 n + 10 个元素,并使用新数组 xi R。是.C() 也不能这样做,只能使用 .Call()?事实上,这就是我想要做的。那是因为我必须更改的 C 代码很大,使用 .C() 会更容易。
    • 这将在同一手册中,在讨论 Calloc() 的同一部分中。我记得,它会调整大小同时删除内容
    • 好的 Dirk,非常感谢您的回答和 cmets。事实上,我已经在 Writing Extensions 中阅读了一些内容。但是有些段落我还是很难理解。我正在浏览你指出的部分。
    【解决方案2】:

    我不会 R 语言,但我会 C。

    当您将指向 x 的指针作为函数 foo 中的参数时,您可以更改 foo 内的 x 的内容,但不能更改 x 本身。

    如果要更改x 的地址,则必须采用“指向x 的指针”,即**x

    在您的foo 实现中,编译器实际上将*x 的值(即内存地址)复制到x(编译器按值传递该地址)。因此,如果您更改函数内部的地址,那么它在外部保持不变。

    对不起,如果我没有解释清楚。

    无论如何,在纯 C 中,代码应该是这样的:

    void foo(double **x)
    {
      int i, n;
    
      n = 4;
      *x = (double*) calloc(n, sizeof(double));
    
      for (i = 0; i < n; i++) {
        (*x)[i] = i;
        printf("%f\n", (*x)[i]); //just to check
      }
    }
    

    这里是工作的 sn-p:https://ideone.com/mRsdUH

    【讨论】:

    • 这个答案就 C 而言是正确的,但不适用于此处提出的问题的 R 上下文。
    • 你说得对。我们不想重新定义轮子。在 R 语言中,SEXP 背后的魔力已经起到了作用。 BTW SEXP 只是一个指向这个结构的指针:typedef struct SEXPREC { SEXPREC_HEADER; union { struct primsxp_struct primsxp; struct symsxp_struct symsxp; struct listsxp_struct listsxp; struct envsxp_struct envsxp; struct closxp_struct closxp; struct promsxp_struct promsxp; } u; } SEXPREC, *SEXP;
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-03
    • 1970-01-01
    • 2015-12-20
    • 1970-01-01
    相关资源
    最近更新 更多