Passing an array of strings across DPI-C

I am curious how the memory is managed by the simulator for DPI calls. I have a working example as below:


module mod;
import "DPI-C" function void dpi_GetStringArray(output string data[]);	    
    string d[3];     
    int len;
	  
   initial begin
       dpi_GetStringArray(d);
		    
       for ( int i = 0; i < 3; i++ ) begin
	   len = d[i].len();
           $display("mod: d[%0d]=%s, len = %0d", i, d[i],len);
       end
    end   
endmodule

//
// c code
//
#include "svdpi.h"

extern void dpi_GetStringArray( const svOpenArrayHandle b )
{
  int left = svLeft(b,1);
  int right = svRight(b,1);
  int i;

  for ( i = 0; i < right-left+1; i++ ) {
    char ** p = (char **) svGetArrElemPtr1(b, i);

    printf("the adress stored is %p\n",p); 
 
    switch(i){
    case(0):{
      *p = "test0000000000000000000000000000000000000000000000000000000000000000000000000";
    }
    break;
    case(1):{
      *p = "test1";
    }
    break;
    case(2):{
      *p = "test2";
    }
    break;
    }//switch

    printf("in C: dpi_GetStringArray p[%d]: %s \n", i, *p);
  }//for
}

The simulation result is:

the adress stored is 0x2aaab3601200
in C: dpi_GetStringArray p[0]: test0000000000000000000000000000000000000000000000000000000000000000000000000
the adress stored is 0x2aaab3601208
in C: dpi_GetStringArray p[1]: test1
the adress stored is 0x2aaab3601210
in C: dpi_GetStringArray p[2]: test2
mod: d[0]=test0000000000000000000000000000000000000000000000000000000000000000000000000, len = 77
mod: d[1]=test1, len = 5
mod: d[2]=test2, len = 5

Here are my questions:

  1. The address gap between the first and second pointer is 0x8 (0x2aaab3601208 - 0x2aaab3601200) as returned by svGetArrElemPtr1(b,1) call. How does it hold a large string? I tried even larger string and it worked. I am confused now. Is there some magic on SV side?
  2. On SV side, when string d[3] is declared as is, how much memory is allocated for each element?

I think I was confused about the string arguments in DPI calls.
I found the following explanation in IEEE1800-2017, H.8.10

— An output mode string does not arrive at the C interface with a meaningful value. It is represented by a const char** variable.

H.8.10.1

—With arrays of string arguments, there is no need for the extra level of indirection that occurs with stand-alone string output and inout arguments. By the rules specified in H.7.8, all arrays of string arguments are represented in C as const char**, regardless of their directionality.

Also in IEEE1800-2017, H.8.7 it says:

input arguments, with the exception of open arrays, are passed by value or by reference, depending on the size. Small values of formal input arguments are passed by value. The following data types are considered small:
— byte, shortint, int, longint, real, shortreal
— Scalar bit and logic
— chandle, string
input arguments of other types are passed by reference.

I always thought “passing by reference” is the same as “passing by pointer”. Can someone help me understand the subtle difference?