Manipulating pointers in C using ctypes

D

Daniel Platz

Hello!

I have to ask a newbie question about manipulating pointers in C using
ctypes. I have a C dll with two functions. The first one creates a
pointer and returns it to python. The second one takes a pointer as an
argument shows its address and the value at which it is pointing. This
I have implemented using the following code

----------- -------- pointers.c ----------------------------
#include <stdio.h>
#ifdef __cplusplus
extern "C" { // only need to export C interface if
// used by C++ source code
using namespace std;
#endif

__declspec(dllexport) void* create()
{
double number = 2.2;
double* ptr = &number;
printf("Pointer address \t %p \n", ptr);
printf("Value at pointer \t %f \n", ptr[0]);
return (void*) ptr;
}

__declspec(dllexport) int show(double* ptr)
{
printf("Pointer address \t %p \n", ptr);
printf("Pointer value \t %f\n", *ptr);
*ptr = 2.4;
printf("New pointer value \t %f\n", *ptr);
return 0;
}

#ifdef __cplusplus
}
#endif
------------------------------------------------------------------------

Please note that in the second function, the show function, I want to
manipulate the value at which the pointer points.
Now, I call this function from python with the following script.

--------------------------- pointers.py --------------------------
import ctypes as ct

# Load dll
pointers = ct.cdll.LoadLibrary('pointers.dll')
getattr(pointers, 'create')
getattr(pointers, 'show')
pointers.create.restype = ct.c_void_p

# Create pointer in C
ptr = pointers.create()

# Show pointer address and value
print 'Adress returned to python ' +hex(ptr)
pointers.show(ct.c_void_p(ptr))
-------------------------------------------------------------------

Calling this script gives me the following output:

Pointer address 0021E508
Value at pointer 2.200000
Adress returned to python 0x21e508
Pointer address 0021E508
Pointer value 0.000000 (2.20000 expected)
New pointer value 2.400000 (2.40000 expected)

But the script returns also an error.

WindowsError: exception: access violation reading 0x40033333
WARNING: Failure executing file: <pointers.py>

Another thing that I find strange is that the return value of
pointers.create is actually an integer instead of an ct.c_void_p
object.

Moreover, I also tried to directly manipulate the address of the
pointer given as an argument to pointers.show. But when it returns to
python the pointer points still at the same address as before the
function call.

Can someone help me with this problem? I would be very glad about an
answer.

With kind regards,

Daniel
 
J

Jason Scheirer

Hello!

I have to ask a newbie question about manipulating pointers in C using
ctypes. I have a C dll with two functions. The first one creates a
pointer and returns it to python. The second one takes a pointer as an
argument shows its address and the value at which it is pointing. This
I have implemented using the following code

----------- -------- pointers.c ----------------------------
#include <stdio.h>
#ifdef __cplusplus
extern "C" {  // only need to export C interface if
              // used by C++ source code
using namespace std;
#endif

__declspec(dllexport) void* create()
{
        double number = 2.2;
        double* ptr = &number;
        printf("Pointer address \t %p \n", ptr);
        printf("Value at pointer \t %f \n", ptr[0]);
        return (void*) ptr;

}

__declspec(dllexport) int show(double* ptr)
{
        printf("Pointer address \t %p \n", ptr);
        printf("Pointer value \t %f\n", *ptr);
        *ptr = 2.4;
        printf("New pointer value \t %f\n", *ptr);
        return 0;

}

#ifdef __cplusplus}

#endif
------------------------------------------------------------------------

Please note that in the second function, the show function, I want to
manipulate the value at which the pointer points.
Now, I call this function from python with the following script.

--------------------------- pointers.py --------------------------
import ctypes as ct

# Load dll
pointers = ct.cdll.LoadLibrary('pointers.dll')
getattr(pointers, 'create')
getattr(pointers, 'show')
pointers.create.restype = ct.c_void_p

# Create pointer in C
ptr = pointers.create()

# Show pointer address and value
print 'Adress returned to python ' +hex(ptr)
pointers.show(ct.c_void_p(ptr))
-------------------------------------------------------------------

Calling this script gives me the following output:

Pointer address          0021E508
Value at pointer         2.200000
Adress returned to python 0x21e508
Pointer address          0021E508
Pointer value    0.000000    (2.20000 expected)
New pointer value        2.400000 (2.40000 expected)

But the script returns also an error.

WindowsError: exception: access violation reading 0x40033333
WARNING: Failure executing file: <pointers.py>

Another thing that I find strange is that the return value of
pointers.create is actually an integer instead of an ct.c_void_p
object.

Moreover, I also tried to directly manipulate the address of the
pointer given as an argument to pointers.show. But when it returns to
python the pointer points still at the same address as before the
function call.

Can someone help me with this problem? I would be very glad about an
answer.

With kind regards,

Daniel

try this:

__declspec(dllexport) void* create()
{
double* ptr = new double;
*ptr = 2.2;
printf("Pointer address \t %p \n", ptr);
printf("Value at pointer \t %f \n", ptr[0]);
return (void*) ptr;
}

Basically once you leave create() the address being used for number is
no longer valid. The other implication for this is you are going to
need a delete() function to free that memory you allocated for the
double as well.
 
M

Mark Tolonen

Daniel Platz said:
Hello!

I have to ask a newbie question about manipulating pointers in C using
ctypes. I have a C dll with two functions. The first one creates a
pointer and returns it to python. The second one takes a pointer as an
argument shows its address and the value at which it is pointing. This
I have implemented using the following code

----------- -------- pointers.c ----------------------------
#include <stdio.h>
#ifdef __cplusplus
extern "C" { // only need to export C interface if
// used by C++ source code
using namespace std;
#endif

__declspec(dllexport) void* create()
{
double number = 2.2;
double* ptr = &number;
printf("Pointer address \t %p \n", ptr);
printf("Value at pointer \t %f \n", ptr[0]);
return (void*) ptr;
}

__declspec(dllexport) int show(double* ptr)
{
printf("Pointer address \t %p \n", ptr);
printf("Pointer value \t %f\n", *ptr);
*ptr = 2.4;
printf("New pointer value \t %f\n", *ptr);
return 0;
}

#ifdef __cplusplus
}
#endif
------------------------------------------------------------------------

Please note that in the second function, the show function, I want to
manipulate the value at which the pointer points.
Now, I call this function from python with the following script.

--------------------------- pointers.py --------------------------
import ctypes as ct

# Load dll
pointers = ct.cdll.LoadLibrary('pointers.dll')
getattr(pointers, 'create')
getattr(pointers, 'show')
pointers.create.restype = ct.c_void_p

# Create pointer in C
ptr = pointers.create()

# Show pointer address and value
print 'Adress returned to python ' +hex(ptr)
pointers.show(ct.c_void_p(ptr))
-------------------------------------------------------------------

Calling this script gives me the following output:

Pointer address 0021E508
Value at pointer 2.200000
Adress returned to python 0x21e508
Pointer address 0021E508
Pointer value 0.000000 (2.20000 expected)
New pointer value 2.400000 (2.40000 expected)

But the script returns also an error.

WindowsError: exception: access violation reading 0x40033333
WARNING: Failure executing file: <pointers.py>

Another thing that I find strange is that the return value of
pointers.create is actually an integer instead of an ct.c_void_p
object.

Moreover, I also tried to directly manipulate the address of the
pointer given as an argument to pointers.show. But when it returns to
python the pointer points still at the same address as before the
function call.

Can someone help me with this problem? I would be very glad about an
answer.

As Jason observed, your create() function creates a number on the local
stack, which becomes invalid once the function returns. If you don't want
to worry about freeing the object created in Jason's solution, you can
create the double in python yourself and let create initialize it:


-------------- pointers.py ----------------------
import ctypes as ct

pointers = ct.CDLL('pointers.dll')
pointers.create.restype = None
pointers.show.restype = None

dbl = ct.c_double()
print ct.byref(dbl),dbl
ptr = pointers.create(ct.byref(dbl))

# Show pointer address and value
print 'Value returned to python: %f' % dbl.value
pointers.show(ct.byref(dbl))
print 'Value returned to python: %f' % dbl.value

-------------- pointers.c ------------------------
#include <stdio.h>

__declspec(dllexport) void create(double* ptr)
{
*ptr = 2.2;
printf("Pointer address %p\n", ptr);
printf("Value at pointer %f\n", *ptr);
}

__declspec(dllexport) void show(double* ptr)
{
printf("Pointer address %p\n", ptr);
printf("Pointer value %f\n", *ptr);
*ptr = 2.4;
printf("New pointer value %f\n", *ptr);
}

-------------- OUTPUT -------------------------
<cparam 'P' (00A05DC8)> c_double(0.0)
Pointer address 00A05DC8
Value at pointer 2.200000
Value returned to python: 2.200000
Pointer address 00A05DC8
Pointer value 2.200000
New pointer value 2.400000
Value returned to python: 2.400000
 
D

Daniel Platz

Thanks for valuable answers. Both solutions work and I understand my
mistake.

Best regards,

Daniel
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top