使用.CALL(不相容的指针类型返回)选自C返回一个值至R时段错误

时间:2019-02-01 17:36:45

标签: c r segmentation-fault

我正在学习使用C编程语言,并且可能遇到不兼容的指针类型返回的问题。

我有与由R读取为data.frame两列的文本文件。看完这个我想执行.CALL在C函数,将读取date.frame并试图返回值时将返回值R中的变量,但发生段错误错误。我找不到解决此问题的方法,有人可以帮助我吗?

文本文件分为两列,如下例所示。

Q0045   YJL166W
Q0045   YDL085W
Q0045   YDR119W-A

这是用于读取data.frame的C代码。

#include <Rinternals.h>
#include <Rdefines.h>
#include <R.h>
#include <stdlib.h>
#include <stdio.h>

char **test(SEXP lst){
  int i,elLength;
  int len = length(lst);
  SEXP col1, col2;
  char ***target = malloc(sizeof(char **) *len);
  col1 = VECTOR_ELT(lst, 0);
  col2 = VECTOR_ELT(lst, 1);
  elLength = length(col1);
  target[0] = malloc(sizeof(char *) * elLength);
  target[1] = malloc(sizeof(char *) * elLength);
  for (i=0; i<elLength; i++) {
    target[0][i] = CHAR(STRING_ELT(col1, i));
    target[1][i] = CHAR(STRING_ELT(col2, i));

  }

  return target;
} 

此后,我在终端中使用命令行创建.so文件:

R CMD SHLIB test.c

最后,R中的代码读取文件并执行.Call。

dyn.load("/home/lab/test.so")
fileR = data.frame(read.table("file.txt", sep = "\t", stringsAsFactors = FALSE))
fileFromC = .Call("test", fileR)

之后,我从终端在R中运行错误:

 *** caught segfault ***
address 0x310000c0, cause 'memory not mapped'

如果我只打印并返回R_NilValue误差不显示。但我需要C工艺的给新变量回归。

2 个答案:

答案 0 :(得分:0)

malloc()不是处理R扩展中内存分配的正确方法。

请查看R文档6.1 Memory allocation部分

  

6.1.1临时存储分配

     

在此,R将在对.C,.Call或.External的调用结束时回收内存。使用

char *R_alloc(size_t n, int size)
     

每个分配n个大小字节单位。

即您可以将此分配器用于要通过C API return进行存储的内存。

答案 1 :(得分:0)

我可以使用下面的代码来完成所需的工作。感谢所有合作的人。

#include <Rinternals.h>
#include <Rdefines.h>
#include <R.h>
#include <stdlib.h>
#include <stdio.h>

char **stripList(SEXP lst){
  int i, j, elLength;
  int len = length(lst);
  char *rans;
  SEXP col1, col2;
  char ***target = (char *) R_alloc(len, sizeof(char **));

  col1 = VECTOR_ELT(lst, 0);
  col2 = VECTOR_ELT(lst, 1);

  elLength = length(col1);

  SEXP ans = PROTECT(Rf_allocMatrix(STRSXP,elLength, len));

  target[0] = malloc(sizeof(char *) * elLength);
  target[1] = malloc(sizeof(char *) * elLength);
  for (i=0; i<elLength; i++) {
    target[0][i] = CHAR(STRING_ELT(col1, i));
    target[1][i] = CHAR(STRING_ELT(col2, i));
  }

for (int i = 0; i < elLength; i++) for (int j = 0; j < len; j++) 
  SET_STRING_ELT(ans, i + j * elLength, Rf_mkChar(target[j][i]));

  UNPROTECT(1);

  return ans;
}