Listing [Python.Docs]: ctypes - A foreign function library for Python.
Couple of thoughts:
"double pointer array" is misleading:
The solution with double pointers (to double :) ) seems a bit complex, (as also specified in the comments). I tend to think it's an XY Problem. Normally, one should only deal with simple pointers, especially if their knowledge in this area isn't very strong (and this seems to apply here, as I noticed from the other questions identical (or very similar) to this one, that you submitted and then deleted)
Anyway, here's a simple example for demo purposes.
dll00.c:
#include <stdlib.h>
#include <stdio.h>
#if defined(_WIN32)
# define DLL00_EXPORT_API __declspec(dllexport)
#else
# define DLL00_EXPORT_API
#endif
#if defined(__cplusplus)
extern "C" {
#endif
DLL00_EXPORT_API double** init(double **ppMat, int m, int n);
DLL00_EXPORT_API int cleanup(double **ppMat, int m);
#if defined(__cplusplus)
}
#endif
DLL00_EXPORT_API double** init(double **ppMat, int m, int n)
{
const double factor = 7.0;
printf("\n----- FROM C: Multiplying input matrix by: %.3f\n", factor);
double **ret = malloc(m * sizeof(double*));
for (int i = 0; i < m; i++) {
ret[i] = malloc(n * sizeof(double));
for (int j = 0; j < n; j++) {
ret[i][j] = ppMat[i][j] * factor;
}
}
return ret;
}
DLL00_EXPORT_API int cleanup(double **ppMat, int m)
{
int ret = 0;
if (ppMat) {
printf("\n----- FROM C: free\n");
for (int i = 0; i < m; i++) {
free(ppMat[i]);
ret++;
ppMat[i] = NULL;
}
free(ppMat);
}
return ++ret;
}
code00.py:
#!/usr/bin/env python
import ctypes as cts
import sys
from pprint import pprint as pp
DLL_NAME = "./dll00.{:s}".format("dll" if sys.platform[:3].lower() == "win" else "so")
def ptr2d_to_mat(ptr, rows, cols):
return tuple(tuple(ptr[i][j] for j in range(cols)) for i in range(rows))
def main(*argv):
dll00 = cts.CDLL(DLL_NAME)
init = dll00.init
cleanup = dll00.cleanup
rows = 4
cols = 6
DblPtr = cts.POINTER(cts.c_double)
DblPtrPtr = cts.POINTER(DblPtr)
init.argtypes = (DblPtrPtr, cts.c_int, cts.c_int)
init.restype = DblPtrPtr
cleanup.argtypes = (DblPtrPtr, cts.c_int)
cleanup.restype = cts.c_int
DblPtrArr = DblPtr * rows
DblArr = cts.c_double * cols
DblArrArr = DblArr * rows
first_value = 6
in_mat = tuple(tuple(range(cols * i + first_value, cols * (i + 1) + first_value)) for i in range(rows))
print("Input matrix:")
pp(in_mat)
in_arr = DblArrArr(*in_mat)
in_ptr = cts.cast(DblPtrArr(*(cts.cast(row, DblPtr) for row in in_arr)), DblPtrPtr) # Cast each row and the final array to (corresponding) pointers
out_ptr = init(in_ptr, rows, cols)
out_mat = ptr2d_to_mat(out_ptr, rows, cols)
cleanup(out_ptr, rows)
print("\nOutput matrix:")
pp(out_mat)
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.\n")
sys.exit(rc)
Output:
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q058226790]> sopr.bat
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
[prompt]> "c:\Install\x86\Microsoft\Visual Studio Community\2017\VC\Auxiliary\Build\vcvarsall.bat" x64>nul
[prompt]> dir /b
code00.py
dll00.c
[prompt]> cl /nologo /DDLL dll00.c /link /NOLOGO /DLL /OUT:dll00.dll
dll00.c
Creating library dll00.lib and object dll00.exp
[prompt]> dir /b
code00.py
dll00.c
dll00.dll
dll00.exp
dll00.lib
dll00.obj
[prompt]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" code00.py
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 064bit on win32
Input matrix:
((6, 7, 8, 9, 10, 11),
(12, 13, 14, 15, 16, 17),
(18, 19, 20, 21, 22, 23),
(24, 25, 26, 27, 28, 29))
----- FROM C: Multiplying input matrix by: 7.000
----- FROM C: free
Output matrix:
((42.0, 49.0, 56.0, 63.0, 70.0, 77.0),
(84.0, 91.0, 98.0, 105.0, 112.0, 119.0),
(126.0, 133.0, 140.0, 147.0, 154.0, 161.0),
(168.0, 175.0, 182.0, 189.0, 196.0, 203.0))
Done.
You can also take a look at [SO]: Problems with passing and getting arrays for a C function using ctypes (@CristiFati's answer), which is very similar (almost identical, I'd say) to this one.