Pass struct from Python to Fortran

I am trying to pass a struct from Python to Fortran as follows

import ctypes as ct
import numpy as np
from numpy.ctypeslib import ndpointer

# import the shared library
fortlib = ct.CDLL('./pass_struct.so') 
f = fortlib.pass_struct

class TestStruct(ct.Structure):
    _fields_ = [("n_nonzeros", ct.c_int),
                ("values", ct.POINTER(ct.c_double)),
                ("nonzeros", ct.POINTER(ct.c_int))]

# Specify arguments type as a pointer to double and an integer
f.argtypes=[ct.POINTER(TestStruct)]

# Create a double array, pass it to Fotran as a pointer
values = np.ones((3), dtype=np.float_, order="F")
values[0] = 1.
values[1] = 2.
values[2] = 3.
values_ptr = values.ctypes.data_as(ct.POINTER(ct.c_double))

nonzeros = np.ones((3), dtype=np.intc, order="F")
nonzeros[0] = 1
nonzeros[1] = 2
nonzeros[2] = 3
nonzeros_ptr = nonzeros.ctypes.data_as(ct.POINTER(ct.c_int))

print("values", values)
print("nonzeros", nonzeros)

test_struct = TestStruct(ct.c_int(3), values_ptr, nonzeros_ptr)

# Call function
f(ct.byref(test_struct))
subroutine pass_struct(st) bind(C, name="pass_struct")
    use iso_c_binding
    implicit none
    
    type, bind(c) :: test_struct
      integer(c_int) :: n_nonzeros
      type(c_ptr) :: values
      type(c_ptr) :: nonzeros
    end type

    type(test_struct), intent(in) :: st

    real(c_float), pointer :: c_values(:)
    integer(c_int), pointer :: c_nonzeros(:)

    print *, "test", st%n_nonzeros
    call c_f_pointer(st % values, c_values, [st%n_nonzeros])
    call c_f_pointer(st % nonzeros, c_nonzeros, [st%n_nonzeros])
    
    print *, "values fortran", c_values
    print *, "nonzeros fortran", c_nonzeros
    
end subroutine pass_struct

Output

values [1. 2. 3.]
nonzeros [1 2 3]
 test           3
 values fortran   0.00000000       1.87500000       0.00000000    
 nonzeros fortran           1           2           3

Otherwise looks fine, but “values fortran”. Do I have a mistake in the code?

edit.
code is compiled with

gfortran -shared pass_struct.f90 -o pass_struct.so 

Probably just this:

Replace it by real(c_double)

Thank you, sir! I’ll by you a beer if I ever meet you :smiley: