[Tutor] Help with using the ctypes module

Luke Paireepinart rabidpoobear at gmail.com
Mon Dec 13 21:54:05 CET 2010


I confess I don't know a lot about C so I may be off base here... But it looks like your c func extendarray returns a pointer to the new extended array, but you are not capturing this pointer in your python when you call the c func. So the python code is pointing at  the old deallocated array.

Does that make sense and/or point you in the right direction?

-----------------------------
Sent from a mobile device with a bad e-mail client.
-----------------------------

On Dec 13, 2010, at 10:27 AM, Sachin Kamboj <backslash42 at gmail.com> wrote:

> Hi All,
> 
> I was trying to use the ctypes module for a project. I was creating a dynamically allocated array of "max_entries" pairs and once the array was exhausted, I was creating a new array of size (1.5 * max_entries) and copying the contents from the old array to the new array. 
> 
> Unfortunately, when I try to access the contents of this new_array, I get a "NULL pointer access" exception. The corresponding C code seems to work perfectly. (See code below.)
> 
> I was wondering if I was missing something about the way the ctypes module works. Any help would be greatly appreciated. (Not sure if this is the appropriate mailing list for my question.)
> 
> /Thanks!
> 
> ---
> 
> #!/usr/bin/env python
> 
> from ctypes import *
> import math
> import random
> 
> 
> class PAIR(Structure):
>     _fields_ = [("a", c_long),
>                 ("b", c_long)]
>                 
> 
> class MY_ARR(Structure):
>     _fields_ = [("no_entries", c_longlong),
>                 ("max_entries", c_longlong),
>                 ("entries", POINTER(POINTER(PAIR)))
>                 ]
> 
> def extendArray(x):
>     print "Extending Array"
>     print "Before: %d/%d" % (x.no_entries, x.max_entries)
>     old_arr = x.entries
>     
>     # Create a new array
>     new_max_entries = int(math.ceil(1.5 * x.max_entries))
>     x.entries = (POINTER(PAIR) * new_max_entries)()
>     
>     # Copy the entries from the old array to the new array
>     for i in range(x.no_entries):
>         x.entries[i] = old_arr[i]
>         
>     x.max_entries = new_max_entries
>     print "After: %d/%d" % (x.no_entries, x.max_entries)
>     return x
> 
> def printPair(x):
>     print x.contents.a, x.contents.b
> 
> def printArray(x):
>     print "Printing %d/%d Entries" % (x.no_entries, x.max_entries)
>     for i in range(x.no_entries):
>         printPair(x.entries[i])
>         
> 
> if __name__ == "__main__":
>     x = MY_ARR(0, 10, (POINTER(PAIR) * 10)())
>     for i in range(100):
>         if x.no_entries == x.max_entries:
>             print "\n\nPrinting Before Extension"
>             printArray(x)
>             
>             extendArray(x)
> 
>             print "\n\nPrinting After Extension"
>             printArray(x)
>         
>         my_pair = PAIR(i, random.randint(0, 100))
>         x.entries[x.no_entries] = pointer(my_pair)
>         x.no_entries += 1
>         
>         printPair(x.entries[i])
>             
>     printArray(x)
> 
> ---
> Now unfortunately, when I try to run this code, I am getting a "NULL pointer access" exception:
> 
> $ python TestExtension.py 
> 0 40
> 1 40
> 2 11
> 3 36
> 4 82
> 5 73
> 6 93
> 7 100
> 8 75
> 9 80
> 
> 
> Printing Before Extension
> Printing 10/10 Entries
> 0 40
> 1 40
> 2 11
> 3 36
> 4 82
> 5 73
> 6 93
> 7 100
> 8 75
> 9 80
> Extending Array
> Before: 10/10
> After: 10/15
> 
> 
> Printing After Extension
> Printing 10/15 Entries
> Traceback (most recent call last):
>   File "TestExtension.py", line 55, in <module>
>     printArray(x)
>   File "TestExtension.py", line 42, in printArray
>     printPair(x.entries[i])
>   File "TestExtension.py", line 37, in printPair
>     print x.contents.a, x.contents.b
> ValueError: NULL pointer access
> 
> ---
> 
> The corresponding C code works perfectly:
> 
> #include <stdio.h>
> #include <stdlib.h>
> #include <math.h>
> 
> typedef struct {
>     long a;
>     long b;
> } pair;
> 
> typedef struct {
>     long long no_entries;
>     long long max_entries;
>     pair **entries;
> } my_arr;
>     
> my_arr *extend_array(my_arr *x) {
>     int i;
>     pair **old_entries = x->entries;
>     long long new_max_entries = ceil(1.5 * x->max_entries);
>     
>     printf("Extending Array\n");
>     printf("Before: %lld/%lld\n", x->no_entries, x->max_entries);
>         
>     x->entries = malloc(sizeof(pair *) * new_max_entries);
>     for (i = 0; i < 100; ++i) {
>         x->entries[i] = old_entries[i];
>     }
>     x->max_entries = new_max_entries;
>     free(old_entries);
>     
>     printf("After: %lld/%lld\n", x->no_entries, x->max_entries);
>     return x;
> }
> 
> void print_pair(pair *p) {
>     printf("%ld\t%ld\n", p->a, p->b);
> }
> 
> void print_array(my_arr *x) {
>     int i;
>     printf("Printing %lld/%lld entries\n", x->no_entries, x->max_entries);
>     for (i = 0; i < x->no_entries; ++i) {
>         print_pair(x->entries[i]);
>     }
> }
> 
> int main(int argc, char *argv[])
> {
>     int i;
>     my_arr x = {
>         0, 
>         10,
>         malloc(sizeof(pair *) * 10)
>     };
>     
>     for (i = 0; i < 100; ++i) {
>         if (x.no_entries == x.max_entries) {
>             extend_array(&x);
>         }
>         pair *my_pair = malloc(sizeof(pair));
>         my_pair->a = i;
>         my_pair->b = rand() % 100;
>         
>         x.entries[x.no_entries++] = my_pair;
>         print_pair(x.entries[i]);
>     }
>     print_array(&x);
>     return 0;
> }
> 
> 
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> http://mail.python.org/mailman/listinfo/tutor
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/tutor/attachments/20101213/56e94551/attachment-0001.html>


More information about the Tutor mailing list