-1

How can I access an 2d array in Fortran which is passed as a pointer from C function. Below is my code

    program linkFwithC
    use iso_c_binding
    implicit none
    interface
      subroutine my_routine(p,r) bind(c,name='print2')
        import :: c_ptr
        import :: c_int
        type(c_ptr), value :: p
        integer(c_int), value :: r
      end subroutine
    end interface
    REAL, POINTER :: PTR2
    integer i,j
    integer,parameter ::n=3
    real (c_double), allocatable, target :: xyz(:,:)
    real (c_double), target :: abc(3,3)
    type(c_ptr) :: cptr
    allocate(xyz(n,n))
    cptr = c_loc(xyz(1,1))

    !Inputing array valyes

    xyz(1,1)= 1
    xyz(1,2)= 2
    xyz(1,3)= 3
    xyz(2,1)= 4
    xyz(2,2)= 5
    xyz(2,3)= 6
    xyz(3,1)= 7
    xyz(3,2)= 8
    xyz(3,3)= 9


    call my_routine(cptr,n)

    do j=1,n
    do i=1,n

    print*,"xyz(i,j)",i,j,xyz(j,i)

    enddo
    enddo
    deallocate(xyz)
 ! pause
  end program linkFwithC

Below is my C code

  #include <stdio.h>
  void print2(double *p, int n)
  {
   printf("Array from C is \n");
   double *dptr;
   int i,j;
   dptr = (double *)p;
   for ( i = 0; i < n; i++)
   {
     for ( j = 0; j<n; j++)
      {
       printf("%.6g \t",dptr[i*n+j]);

      *(p+i*n+j)=1;
      printf("\n");
     }
  }
 }

Below is the output

Array from C is
1       4       7
1       5       8
1       6       9
 xyz(i,j)           1           1   1.00000000000000
 xyz(i,j)           2           1   1.00000000000000
 xyz(i,j)           3           1   1.00000000000000
 xyz(i,j)           1           2   4.00000000000000
 xyz(i,j)           2           2   5.00000000000000
 xyz(i,j)           3           2   6.00000000000000
 xyz(i,j)           1           3   7.00000000000000
 xyz(i,j)           2           3   8.00000000000000
 xyz(i,j)           3           3   9.00000000000000
*** glibc detected *** ./main.exe: free(): invalid next size (normal): 0x000000000093c290 ***
======= Backtrace: =========
/lib64/libc.so.6[0x320ea75f4e]
/lib64/libc.so.6[0x320ea78cf0]
./main.exe[0x408786]
./main.exe[0x4240bc]
./main.exe[0x429f54]
./main.exe[0x402e63]
/lib64/libc.so.6(__libc_start_main+0xfd)[0x320ea1ed5d]
./main.exe[0x402d69]
======= Memory map: ========

I am not able to print the modified values in Fortran. Can anyone suggest what could be possible reason for wage output?

  • you already asked a lot of questions like this: http://stackoverflow.com/questions/27584674/passing-2d-array-from-fortran-to-c, http://stackoverflow.com/questions/27582715/passing-a-two-dimentional-array-from-fortran-to-c – Jean-François Fabre Sep 30 '16 at 20:35
  • are you sure that 2-dimensional allocatable arrays in fortran have contiguous memory like static 2-dimensional arrays? Because the result seem to prove the contrary. And don't forget that C & FORTRAN are transposed when it comes to multidimensional arrays. – Jean-François Fabre Sep 30 '16 at 20:37
  • @Jean-FrançoisFabre Yes they have, in fact they always are contigous memory. You can google for a sample program that passes a pointer from [tag:c] to *lapack* [tag:fortran]. – Iharob Al Asimi Sep 30 '16 at 21:03
  • @iharob I was asking because it looked like they aren't don't you agree? I'm not a FORTRAN specialist at all. Just adding fuel to the debate :) – Jean-François Fabre Sep 30 '16 at 21:08
  • could you [edit] your C code and replace `*(p+i*n+j)=1;` by `*(p+i*n+j)=i*n+j;` (and the associated output of course). – Jean-François Fabre Sep 30 '16 at 21:45
  • Any reason you don't use a 2D array in the C code? And never use unnecessary casts! Both `p` and `dptr` have the same type, so why the cast? – too honest for this site Sep 30 '16 at 21:50
  • @Olaf C doesn't have true 2D arrays, except of limited static ones and VLAs. You have to create array of pointers to row in C and that is annoying. – Vladimir F Героям слава Oct 01 '16 at 09:54
  • @VladimirF: That is plain nonsense! You can declare multidimensional arrays anywhere you can declare other objects, pass pointers to them to/from functions and of course allocate them dynamically without problem. It is just than many people don't understand the syntax and use jagged arrays (which are indeed annoying if you want a 2D array)! But it is not lack of the language, but the coders. – too honest for this site Oct 01 '16 at 17:34
  • @Olaf That no pute nonsense at al! It is pretty difficult to create a 2d contiguous dynamic array in C. You DO have to create 1D array of pointers separately. – Vladimir F Героям слава Oct 01 '16 at 18:48
  • @VladimirF: `int (*a2d)[COLS] = malloc(ROWS * sizeof(*a2d)); ... ; free(a2d);` is difficult? Good joke! As I wrote: that nonsense is spread by ppl who don't know the language! Oh, and despite using uppercase, `ROWS` and `COLS` can as well be variables! – too honest for this site Oct 01 '16 at 21:49
  • @Olaf I know it well, dont worry, it is convoluted enough. – Vladimir F Героям слава Oct 01 '16 at 22:00
  • @VladimirF: I don't see what is convoluted. It only is if you have not undestood declarations and preceedence correctly. That is much easier than a jagged array and indeed **is** guaranteed continuous. If you want something simpler, C is not "your" language. – too honest for this site Oct 01 '16 at 22:03

1 Answers1

0

First of all, your code is not FORTRAN, but Fortran; facilities for C-language interoperability came much later. Second, the following code

#include <stdio.h>
void print2(double *p, int n)
{  
  double *dptr;
  int i,j;

  /* Why are you making a copy here? 
   * Did you intent to pass by value or reference?
   */
  dptr = p;
  printf("Array from C is \n");
  for(i = 0; i < n; i++){
    for(j = 0; j < n; j++){
      printf("%.6g \t", dptr[i*n+j]);
      *(p+i*n+j)=1;
      printf("\n");
    }
  }
}

module mymod

  use ISO_C_binding, only: &
       c_ptr, &
       c_int

  ! Explicit typing only
  implicit none

  interface
     subroutine my_routine(p, r) bind(c, name='print2')
       import :: c_ptr, c_int
       type(c_ptr), value    :: p
       integer(c_int), value :: r
     end subroutine my_routine
  end interface

end module mymod

program main

    use ISO_Fortran_env, only: &
    compiler_version, &
    compiler_options

    use ISO_C_binding, only: &
     c_double, &
     c_ptr, &
     c_loc

    use mymod, only: &
     my_routine

    ! Explicit typing only
    implicit none

    integer i, j
    integer, parameter :: N = 3
    real(c_double), allocatable, target :: xyz(:,:)
    type(c_ptr) :: cptr

    ! Allocate memory
    allocate(xyz(N, N))

    ! Get C-language address
    cptr = c_loc(xyz(1,1))

    ! Inputting array values
    xyz(1,1)= 1
    xyz(1,2)= 2
    xyz(1,3)= 3
    xyz(2,1)= 4
    xyz(2,2)= 5
    xyz(2,3)= 6
    xyz(3,1)= 7
    xyz(3,2)= 8
    xyz(3,3)= 9

    call my_routine(cptr, N)

    do j=1, N
       do i=1, N
      print *, "xyz(i,j)", i, j, xyz(j, i)
       end do   
    end do

    ! Release memory
    deallocate(xyz)

    print '(/4a/)', &
    ' This file was compiled using ', compiler_version(), &
    ' using the options ', compiler_options()

end program main

yields

gfortran -Wall -o main.exe  print2.c mymod.f90 main.f90
./main.exe

Array from C is 
1   
4   
7   
2   
5   
8   
3   
6   
9   
 xyz(i,j)           1           1   1.0000000000000000     
 xyz(i,j)           2           1   1.0000000000000000     
 xyz(i,j)           3           1   1.0000000000000000     
 xyz(i,j)           1           2   1.0000000000000000     
 xyz(i,j)           2           2   1.0000000000000000     
 xyz(i,j)           3           2   1.0000000000000000     
 xyz(i,j)           1           3   1.0000000000000000     
 xyz(i,j)           2           3   1.0000000000000000     
 xyz(i,j)           3           3   1.0000000000000000     

 This file was compiled using GCC version 6.1.1 20160802 using the options -mtune=generic -march=x86-64 -Wall
jlokimlin
  • 593
  • 4
  • 9