2010-12-13 7 views
3

プロジェクト用にctypesモジュールを使用しようとしていました。私は動的に割り当てられた "max_entries"配列の配列を作成していました。そして、配列が使い尽くされたら、サイズの新しい配列(1.5 * max_entries)を作成し、古い配列の内容を新しい配列にコピーしていました。Python ctypes module:ポインタ配列の拡張中にポインタがNULLにアクセスする

残念ながら、このnew_arrayの内容にアクセスしようとすると、「NULLポインタアクセス」例外が発生します。対応するCコードは完全に動作するようです。 (下のコードを参照してください)

私はctypesモジュールの動作方法について何か不足していたのだろうかと思っていました。どんな助けでも大歓迎です。 (これが私の質問の適切なメーリングリストであるかどうか不明)

/ありがとう!

$ 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 

対応するCコードの作品:私はこのコードを実行しようとする今、残念ながら、私は "NULLポインタアクセス" の例外を取得しています


#!/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) 

完全:

#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; 
} 

答えて

2

問題は声明

old_arr = x.entries 

はあなたにそれを期待して何をしないということです。 old_arr._b_base_を見て、それがMY_ARRを指しているポインタであることがわかります。したがって、元のポインタが変更されると、old_arrは突然新しい配列を指し、ループはヌルポインタをたくさん割り当てます。これを修正するには、

new_max_entries = int(math.ceil(1.5 * x.max_entries)) 
new_entries = (POINTER(PAIR) * new_max_entries)() 

# Copy the entries from the old array to the new array 
for i in range(x.no_entries): 
    new_entries[i] = x.entries[i] 

x.entries = new_entries 
x.max_entries = new_max_entries