1

I am passing numpy arrays to C code using ctypes. I would like to keep that information in a C structure. I have the following code in C:

my_file.h

typedef struct container
{
    int nb_rows;
    int nb_cols;
    double ** data;
};
void save_d2_double(int nb_rows, int nb_cols, double *data[nb_cols]);
void print_container();

my_file.c

#include <stdio.h>
#include "my_file.h"    

struct container c;

void save_d2_double(int nb_rows, int nb_cols, double * data[nb_cols] ){
    c.nb_rows = nb_rows;
    c.nb_cols = nb_cols;
    c.data = data;
}

void print_container(){
   printf("\n");
   printf("%d\t%d", c.nb_rows, c.nb_cols);
   for(int i = 0; i < c.nb_rows; i++){
       for(int j = 0; j < c.nb_cols; j++){
           printf("%f\t", c.data[i][j]); \\ Error here
       }
       printf("\n");
   }
   printf("\n");
}

And the following in python:

my_file.py

import numpy as np
import numpy.ctypeslib as npct
import ctypes

LIBC = ctypes.CDLL("my_file.so")
array_2d_double = npct.ndpointer(dtype=np.double, ndim=2)
LIBC.save_d2_double.restype = None
LIBC.save_d2_double.argtypes = [ctypes.c_int, ctypes.c_int, array_2d_double]
LIBC.print_container.restype = None
LIBC.print_container.argtypes = []

# The shape of this array vary in the end application.
x_2d_d = np.array([[1.,2.,3.,10.],[4.,5.,6.,11.],[7.,8.,9.,12.]], dtype=np.float64)

shape = x_2d_d.shape
LIBC.save_d2_double(shape[0], shape[1], x_2d_d)
LIBC.print_container()

When I want to access c.data I get:

Segmentation fault (core dumped)

I suspect that the problem is in the declaration of double ** data; however, since C doesn't know in advance the dimensions of the numpy array, I don't know how to declare this filed.

Thanks in advance !

1
  • @ Joseph Sible-Reinstate Monica, You helped me out with questinos about ctypes before. Do you have suggestions for this one? Commented Nov 21, 2020 at 18:23

1 Answer 1

1

First problem: double *data[nb_cols] is an array of pointers, or equivalently a double pointer, but that's not what Python is passing. Python is passing a 2D array, or equivalently a pointer to an array, so your function should take double (*data)[nb_cols] instead.

Second problem: C doesn't let you store a pointer to a VLA in a struct. You tried to use a double pointer instead, but a double pointer isn't compatible with a pointer to an array. However, there is a solution: since arrays are contiguous, you can instead treat the pointer as if it were just a pointer to the first element, and then cast it to a pointer to a VLA in the function where you use it (or manually convert the indices instead).

my_file.h:

struct container
{
    int nb_rows;
    int nb_cols;
    double *data;
};
void save_d2_double(int nb_rows, int nb_cols, double *data); /* or double (*data)[nb_cols] */
void print_container(void);

my_file.c:

#include <stdio.h>
#include "my_file.h"    

struct container c;

void save_d2_double(int nb_rows, int nb_cols, double *data) { /* or double (*data)[nb_cols] */
    c.nb_rows = nb_rows;
    c.nb_cols = nb_cols;
    c.data = data;
}

void print_container(void) {
   double (*data)[c.nb_cols] = (double (*)[c.nb_cols])c.data; /* optional; see below */
   printf("\n");
   printf("%d\t%d", c.nb_rows, c.nb_cols);
   for(int i = 0; i < c.nb_rows; i++) {
       for(int j = 0; j < c.nb_cols; j++) {
           printf("%f\t", data[i][j]); /* or c.data[i * c.nb_cols + j] */
       }
       printf("\n");
   }
   printf("\n");
}
Sign up to request clarification or add additional context in comments.

6 Comments

Dear @Joseph Sible, you are a life saver. What should I read to learn all these nuances?
@mm_ I just picked this up over time and can't really point to a single source where I learned it.
@ Joseph Sible, could you unpack double (*data)[c.nb_cols] = (double (*)[c.nb_cols])c.data; please? How would you do it for a 3 dim or 4 dim array?
@mm_ There should be a separate [] for every dimension but the first. So something like double (*data)[c.nb_cols][c.nb_third_dimension_size][c.nb_fourth_dimension_size]
@mm_ You should post a new question for that with all of your code and the exact problem details.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.