I've followed suggestions in threads like this one 
on how to pass arrays of values from c++ to c#. after @CodyGray's comment on my recent question here why I'm using pointers at all i tried to pass values without pointers and marshal code, also following this
 and it works too! I'm confused, what's the correct/best way to do it? why use pointers here at all?
here's some code:
consider this exported c++ function
extern "C" { __declspec(dllexport) void PointerTest(char ** text, float* fArray, int * iArray); }
here's what I did until now in c#:
[System.Runtime.InteropServices.DllImport("myTest.dll")]
        private static extern void PointerTest(IntPtr text, IntPtr fArray, IntPtr iArray);
public static IntPtr NativeUtf8FromString(string managedString) {
            int len = Encoding.UTF8.GetByteCount(managedString);
            byte[] buffer = new byte[len + 1];
            Encoding.UTF8.GetBytes(managedString, 0, managedString.Length, buffer, 0);
            IntPtr nativeUtf8 = Marshal.AllocHGlobal(buffer.Length);
            Marshal.Copy(buffer, 0, nativeUtf8, buffer.Length);
            return nativeUtf8;
            }
public void DoSomething(String text, float[] F, int[] I, int numFloats, int numInts){
            IntPtr sPtr = NativeUtf8FromString(text);
            IntPtr fPtr = Marshal.AllocHGlobal(numFloats*sizeof(float));
            IntPtr iPtr = Marshal.AllocHGlobal(numInts*sizeof(int));
            try
            {           
                Marshal.Copy(F, 0, fPtr, numFloats);
                Marshal.Copy(I, 0, iPtr, numInts);
                PointerTest(sPtr, fPtr, iPtr);
            }
            finally
            {
                Marshal.FreeHGlobal(sPtr);
                Marshal.FreeHGlobal(fPtr);
                Marshal.FreeHGlobal(iPtr);      
            }
        }
this works fine when passing values from c# to c++; however, the only way of passing values back (reliably) using pointers i found was the return value of my function, causing me to stuff all kinds of values in one big array and return that (again by reference).
now consider this code:
[System.Runtime.InteropServices.DllImport("myTest.dll")]
        private static extern void PointerTest([In, Out] String text, [In, Out] float[] fArray, [In, Out] int[] iArray);
public void DoSomething(String text, float[] F, int[] I){   
            PointerTest(text, F, I);
            }
This does the same thing as far as I can tell. Plus by using the [In, Out] semantic I can easily access the modified arrays after I've called PointerTest.
Now what am I missing here? Obviously the second approach is much cleaner, easier to understand for beginners like me and still the standard answer online is use pointers/the first approach....which leads me to the conclusion there must be something wrong in the second approach, but then i got it from msdn....
please help me understand this. thanks in advance.