3

C code: uses fractal_create() to assign a 2D array to 'values' array in the struct fractal_t

//2D.c

#include <stdlib.h>
#include <stdio.h>

typedef struct 
{
    size_t height;
    size_t width;
    double values[];
} fractal_t;

void fractal_destroy (fractal_t* f)
{
    free(f);
}

void fractal_fill (fractal_t* f)
{
    double (*array_2D)[f->width] = (double(*)[f->width]) f->values;

    for (size_t height=0; height < f->height; height++)
    {
        for (size_t width=0; width < f->width; width++)
        {
            array_2D[height][width] = width; // whatever value that makes sense
        }
    }
}

void fractal_print (const fractal_t* f)
{
    double (*array_2D)[f->width] = (double(*)[f->width]) f->values;

    for(size_t height=0; height < f->height; height++)
    {
        for(size_t width=0; width < f->width; width++)
        {
            printf("%.5f ", array_2D[height][width]); 
        }
        printf("\n");
    }
}

fractal_t* fractal_create (size_t height, size_t width)
{
    // using calloc since it conveniently fills everything with zeroes
    fractal_t* f = calloc(1, sizeof *f + sizeof(double[height][width]) );
    f->height = height;
    f->width = width;
    // ...
    fractal_fill(f); // fill with some garbage value
    fractal_print(f);
    return f;
}

int main (void)
{
    int h = 3;
    int w = 4;

    fractal_t* fractal = fractal_create(h, w);
    fractal_destroy(fractal);
}

I'm trying to access this 'values' 2D array from python using ctypes

python code:

from ctypes import *

h = 3
w = 4

class fractal_t(Structure):
    _fields_ = [("a", c_int),
                ("values", (c_double * h) * w)]

slib = cdll.LoadLibrary('/2D.so')
t = fractal_t
fun = slib.fractal_create
t  = fun(c_int(h), 
    c_int(w))

p1 = fractal_t.from_address(t)

print(p1.values[0][0])
print(p1.values[0][1])
print(p1.values[0][2])

for i in p1.values: 
    print(i, end=" \n")
    for j in i:
        print(j, end=" \n")

output:

0.00000 1.00000 2.00000 3.00000 
0.00000 1.00000 2.00000 3.00000 
0.00000 1.00000 2.00000 3.00000 
2e-323
0.0
1.0
<__main__.c_double_Array_3 object at 0x7f5c7836f8c8> 
2e-323 
0.0 
1.0 
<__main__.c_double_Array_3 object at 0x7f5c7836fb70> 
2.0 
3.0 
0.0 
<__main__.c_double_Array_3 object at 0x7f5c7836f8c8> 
1.0 
2.0 
3.0 
<__main__.c_double_Array_3 object at 0x7f5c7836fb70> 
0.0 
1.0 
2.0 

The first 3 lines from the output is printed from fractal_print()in C. When i tried to access the 2D array using p1.values[0][0], I'm not getting the correct value. Not sure what is wrong here.

2
  • What happens if you replace (c_double * h) * w with (c_double * w) * h? Commented May 26, 2020 at 21:25
  • It changes rows to columns <__main__.c_double_Array_4 object at 0x7fba3d4d68c8> 2e-323 0.0 1.0 2.0 <__main__.c_double_Array_4 object at 0x7fba3d4d6b70> 3.0 0.0 1.0 2.0 <__main__.c_double_Array_4 object at 0x7fba3d4d68c8> 3.0 0.0 1.0 2.0 Commented May 26, 2020 at 21:31

1 Answer 1

1

I resolved this

Python code:

import numpy
from ctypes import *

col = 2
row = 3

lib = cdll.LoadLibrary('./2d_array.so')

class Array_2d(Structure):
    _fields_ = [('col', c_int), 
                ('row', c_int),
                ("data", (c_double * row) * col)]


fun = lib.initialize_Array_2d
point_ptr = fun(c_int(col), c_int(row))

fun = lib.cfun
fun(c_void_p(point_ptr))

p1 = Array_2d.from_address(point_ptr)

print("from python")

print(p1.data[0][0], p1.data[0][1],p1.data[0][2])
print(p1.data[1][0], p1.data[1][1],p1.data[1][2])

fun = lib.free_Array_2d
point_ptr = fun()

C code:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int col;
    int row;
    double data[];
} Array_2d;

Array_2d* f;

Array_2d* initialize_Array_2d(int col, int row)
{
    f = calloc(1, sizeof *f + sizeof(double[col][row]));
    f->col = col;
    f->row = row;
    return f;
}

void free_Array_2d()
{
    free(f);
}

void cfun(void * stv) 
{
    Array_2d * f = (Array_2d *) stv;

    double (*array_2D)[f->row] = (double(*)[f->row]) f->data;

    for (size_t i=0; i < f->col; i++)
    {
        for (size_t j=0; j < f->row; j++)
        {
            array_2D[i][j] = rand() % 10 + 1; // some random values
        }
    }

    printf("from C : \n");
    for(size_t i=0; i < f->col; i++)
    {
        for(size_t j=0; j < f->row; j++)
        {
            printf("%.1f ", array_2D[i][j]); 
        }
        printf("\n");
    }
    printf("\n");
}

Output:

from C : 
4.0 7.0 8.0 
6.0 4.0 6.0 

from python
4.0 7.0 8.0
6.0 4.0 6.0
Sign up to request clarification or add additional context in comments.

5 Comments

I think you mixed up C and Python.
is there any drawback in that?
Thank you for the comment. Could you point out what in the code is causing Undefined Behaviour. (I believe there are no inconsistencies between arguments (and / or return) in the above code as you have explained in the link provided)
There are no inconsistencies as in there are no specifications whatsoever.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.