Hello All,
I've been trying to find more resources/documentation about how to convert python lists to C arrays (and vice versa) when writing a python extension. Surprisingly, there's very little one can find about this even though it must be a fairly common procedure. I looked through official python guide on "Extending and Embedding the Python Interpreter" but it's very terse on examples and the important topic on reference counting is still not very clear. I also found one or two examples of similar operations on this list postings (from 6 years ago!) but they didn't quite explain all I need to know.
Here is the code I was trying to use to convert two lists (one is a list of strings with the same length and the other is a list of doubles) to C arrays in a C extension:
typedef char Name[5];
extern void parseMask(int, char*, Name *, double *); /* this is the function I am
trying to wrap */
static PyObject *print_sel(PyObject *self, PyObject *args) { PyObject *anamestr, *xdbl; PyObject *pylist; /* return list of 0/1 */ PyObject *item; int nat; int i, k; Name *aname; double *x;
PyArg_ParseTuple(args,"iOO", &nat, &anamestr, &xdbl); if (!PySequence_Check(anamestr) || !PySequence_Check(xdbl)) { PyErr_SetString(PyExc_TypeError, "expected sequence"); return NULL; } /* create dynamic C arrays */ aname = (Name *) malloc(sizeof(Name)*nat); x = (double *) malloc(sizeof(double)*nat);
for (i = 0; i < nat; i++) { /* get the element from the list*/ item = PySequence_GetItem(anamestr,i); /* check that item != NULL, i.e. make sure it is Python string */ if (!PyString_Check(item)) { free(aname); /* free up the memory before leaving */ free(x); PyErr_SetString(PyExc_TypeError, "expected sequence of strings"); return NULL; } /* assign to the C array */ strcpy(aname[i], PyString_AsString(item)); Py_DECREF(item);
item = PySequence_GetItem(xdbl,i); if (!PyFloat_Check(item)) { free(aname); free(x); PyErr_SetString(PyExc_TypeError, "expected sequence of integers"); return NULL; } x[i] = PyFloat_AsDouble(item); Py_DECREF(item); }
Then I call the function "parseMask" (which I am trying to wrap in this extension) which returns a C array (integer array, elements are either 0 or 1). Now I need to convert this integer array to python list and return it back to python. Here is the code for that:
result = (int *) malloc(sizeof(int) * nat); parseMask(...) -> returns int array result
pylist = PyTuple_New(nat); for (i = 0; i < nat; i++) { /* convert resulting array [0/1] to PyObject */ if (result[i] == 0) item = PyInt_FromLong(0); else item = PyInt_FromLong(1);
PyTuple_SetItem(pylist, i, item); Py_DECREF(item); }
/* free up all arrays before leaving */ free((void *) aname); free((void *) x); free((void *) result);
return pylist;
I was wondering if some 'extension guru' (or whoever has experience with writing extensions :-)) could see if the above code is correct, especially with respect to reference counting. When I use this extension from Python (on Fedora Core 3, Python2.3) I get the following error:
*** glibc detected *** double free or corruption (out): 0x09f724e8 *** Aborted
This is supposed to mean some deeper memory allocation/deallocation error. I suspect I am not creating or releasing python objects in my C extension above correctly. Of course, it is also possible that the C function I am wrapping (parseMask()) is not allocating memory properly, but it works without problem when I call it from a C program.
I am sorry for this looong post, but I didn't see a way to make it shorter and still be very specific about what I am trying to do...
Many thanks for any help, -Viktor Hornak
_______________________________________________ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor