Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

583
Vistas
Convertir doble[,] a IntPtr C#

Necesito convertir una matriz doble en c# en un IntPtr para enviarlo correctamente a mi c DLL. He podido convertir con éxito de IntPtr a double[,] usando el método de esta respuesta . También encontré otra respuesta que está cerca de lo que necesito pero trata con matrices 1D.

Me falta algo en mi lógica y obtengo el código de error después de un bloqueo: Managed ' ha salido con el código -1073740940 (0xc0000374).

Esto es lo que tengo hasta ahora

 IntPtr p = Marshal.AllocHGlobal(rows * columns); for (int i = 0; i < rows; i++) //rows { double[] temp = new double[columns]; for (int x = 0; x < columns; x++) temp[x] = input.cells[i, x]; Marshal.Copy(temp, 0, p, columns); p = (IntPtr)(p.ToInt64() + IntPtr.Size); } toReturn.cells = p; Marshal.FreeHGlobal(p); return toReturn;

toReturn.cells es mi IntPtr dentro de una estructura que devuelvo. las celdas están estructuradas como celdas [filas, columnas]

Los IntPtr todavía son muy nuevos para mí.

Editar: gracias a Harold. sus sugerencias funcionaron maravillosamente

over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

Hay varias cosas mal con eso.

Primero, rows * columns no es el tamaño de los datos, es solo el número total de elementos. Los elementos no son de un byte cada uno, sino de ocho, o sizeof(double) si lo prefiere.

En segundo lugar, p se actualiza mediante p = (IntPtr)(p.ToInt64() + IntPtr.Size); (es decir, avanzándolo en 4 u 8 bytes dependiendo de qué tan grandes sean los punteros en el modo actual), pero ha escrito columns * 8 (o columns * sizeof(double) ) bytes de datos. Avanzar p en menos de columns * 8 hace que las escrituras se sobrescriban entre sí, por lo que no todos los datos terminan en el resultado. Por cierto, las conversiones complicadas aquí en realidad no son necesarias, puede agregarlas directamente a un IntPtr , desde .NET 4.

En tercer lugar, se cambia p en el ciclo, lo que no es malo por sí solo, pero se hace de una manera que pierde el rastro del puntero original. toReturn.cells = p; y Marshal.FreeHGlobal(p); use una p que no se refiera al área que asignó, usan una p que ahora apunta justo más allá del final de los datos (bueno, apuntaría allí si p se actualizara en la cantidad correcta). Debe recordarse la p original.

En cuarto lugar, liberar los datos antes de devolverlos significa que ahora ya no existen, por lo que cualquier código al que se pasen estos datos todavía no los tiene: tiene un puntero a nada que no será válido para usar (puede funcionar accidentalmente, pero es peligroso e incorrecto).

Los tres primeros puntos son fáciles de arreglar, pero el último necesita un cambio no local en el funcionamiento de su aplicación: la memoria no se puede liberar aquí, pero debería liberarse en algún momento, es decir, cuando el usuario de los datos haya terminado. con eso.

Algunas correcciones aplicadas:

 int stride = columns * sizeof(double); IntPtr p = Marshal.AllocHGlobal(rows * stride); for (int i = 0; i < rows; i++) //rows { double[] temp = new double[columns]; for (int x = 0; x < columns; x++) temp[x] = input.cells[i, x]; Marshal.Copy(temp, 0, p + stride * i, columns); } toReturn.cells = p; return toReturn;

Tenga en cuenta que aún debe liberar la memoria en el momento adecuado.

over 4 years ago · Santiago Trujillo Denunciar

0

¿Qué pasa con el uso de GHandles para llevar el IntPtr a una matriz? Primero hice una copia para evitar que el cliente sobrescribiera los datos. Desafortunadamente, debe mantener un GHandle para llamar a .Free() para evitar pérdidas de memoria. Esto impulsa la decisión de mantener no solo un IntPtr en las salidas, sino también el GHandle y la longitud de bytes FYI.

 static class Program { static void Main(string[] args) { Inputs inputs = new Inputs(); inputs.Cells = new double[,] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; var outputs = Prepare(inputs); Console.WriteLine(outputs.CellPtr); Console.WriteLine("Finish."); } static Outputs Prepare(Inputs inputs) { Outputs outputs = new Outputs(); outputs.ByteSize = Buffer.ByteLength(inputs.Cells); var temp = new double[inputs.Cells.GetLength(0), inputs.Cells.GetLength(1)]; Buffer.BlockCopy(inputs.Cells, 0, temp, 0, outputs.ByteSize); outputs.Handle = GCHandle.Alloc(inputs.Cells, GCHandleType.Pinned); outputs.CellPtr = outputs.Handle.AddrOfPinnedObject(); return outputs; } } public class Inputs { public double[,] Cells { get; set; } } public class Outputs : IDisposable { public IntPtr CellPtr { get; set; } public int ByteSize { get; set; } public GCHandle Handle { get; set; } #region IDisposable Support private bool disposedValue = false; // To detect redundant calls protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { // dispose managed resources here } Handle.Free(); CellPtr = IntPtr.Zero; ByteSize = 0; disposedValue = true; } } ~Outputs() { // Do not change this code. Put cleanup code in Dispose(bool disposing) above. Dispose(false); } // This code added to correctly implement the disposable pattern. public void Dispose() { Dispose(true); } #endregion }
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda