Ir al contenido


Foto

punteros dobles y matrices en DELPHI


  • Por favor identifícate para responder
21 respuestas en este tema

#1 Flack

Flack

    Newbie

  • Miembros
  • Pip
  • 5 mensajes

Escrito 03 febrero 2014 - 12:33

hola todos,

requiero saber como declarar un puntero doble o puntero de puntero en Delphi, para C++ sería asi:
double **a, pero no se como declararlo en Delphi. Requiero para llamar una Dll que usa esa variable. Gracias
  • 0

#2 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 03 febrero 2014 - 01:49

Observa este código:


delphi
  1. type PDWORD = ^DWORD;
  2. type PPDWORD = ^PDWORD;
  3.  
  4. //....................
  5. var
  6.   uno: PPDWORD;
  7.   dos: PDWORD;
  8.   tres: DWORD;
  9. begin
  10.   tres:= 1;
  11.   dos:= @tres;
  12.   uno:= @dos;
  13.   (uno^)^:=3;
  14. end;



Pero en delphi las matrices no son como en C. Puedes ver una discusión de este tema aquí.


Saludos.
  • 0

#3 Flack

Flack

    Newbie

  • Miembros
  • Pip
  • 5 mensajes

Escrito 04 febrero 2014 - 08:21

Gracias por la ayuda!! una ultima pregunta, esta variable "a" es una matriz como sería esta parte: (uno^)^:= 3;???
  • 0

#4 Sergio

Sergio

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.092 mensajes
  • LocationMurcia, España

Escrito 04 febrero 2014 - 09:11

Si a es una matriz real de 2 dimensiones de 10x20 elementos (si es de 3 sería similar) sería algo como esto:



delphi
  1. var
  2.   a: array of array of double;
  3. begin
  4.   // Dimensiono la matriz:
  5.   SetLength(a, 10);
  6.   // Cada sub-elemento es otra matriz de longitud variable
  7.   for i:= Low(a) to High(a) do
  8.     SetLength(a[i], 20);
  9.   // nota: Puedo añadir huecos si los necesito:
  10.   SetLength(a[0], 21);
  11.   // Para acceder a un elemento, solo haces esto:
  12.   Valor:= a[i, j];



Esto es con matrices de largo variable, si fuesen fijas mas sencillo:



delphi
  1. var
  2.   a: array [0..9] of array [0..19] of double;
  3. begin
  4.   // Para acceder a un elemento, solo haces esto:
  5.   Valor:= a[i, j];




  • 0

#5 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 04 febrero 2014 - 09:18

Sergio, recuerda que si la 2da dimensión de la matriz es la misma para todas las filas basta con hacer:



delphi
  1. SetLength(A, 10, 20); // Esto crea una matriz de 10x20



Sólo en caso de que cada fila tenga una dimensión variable es necesario tu enfoque. Mientras pueda evitarse el hacer repetidamente SetLength, mucho mejor.

Este enfoque puede extenderse incluso a órdenes mayor. Por ejemplo:



delphi
  1. SetLength(A, 10, 20, 30);



Crea un arreglo de dimensiones 10x20x30. Esto de plano ya nos permite abstraernos como para trabajar con operaciones en el espacio. Clarísimo ejemplo el uso de vectores en la geometría euclidiana.

Con una cuarta dimensión:



delphi
  1. SetLength(Dim1, Dim2, Dim3, Dim4);



Ya podemos incluso ver al espacio junto al tiempo. Otra posible aplicación de un arreglo de 4 dimensiones podría ser para implementar los cuaterniones.  :p Aunque para el caso se me hace más elegante un tipo record:



delphi
  1. type Cuaternion = record
  2.           r, i, j, k: Double;
  3.         end;



Siendo r el componente real e i, j, y k los componentes imaginarios. Y hasta allí llega mis conocimientos de Física  :D

Saludos,
  • 0

#6 Flack

Flack

    Newbie

  • Miembros
  • Pip
  • 5 mensajes

Escrito 04 febrero 2014 - 11:50

Entiendo la idea de como usar una matriz, el problema es usar una matriz que sea puntero de puntero entonces seriá asi:??

(a^[i,j])^ := 3; ????

  • 0

#7 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 04 febrero 2014 - 12:10

Entiendo la idea de como usar una matriz, el problema es usar una matriz que sea puntero de puntero entonces seriá asi:??

(a^[i,j])^ := 3; ????

Hola Flack,
Mucho me temo que no es tan sencillo, pues como ha comentado escafandra unos mensajes antes al dejarte el link a otro hilo en donde se ha debatido el uso de matrices por punteros mediante diversas técnicas (GetMem vs VirtualAlloc) las cosas son más rebuscadas.
En ese hilo se puede ver en claro en los códigos que amablemente escafandra aportó los diversos castings y lios que se necesita por parte de Delphi.
Simplemente en C (y seguramente en C++) y Delphi el manejo de punteros y de arreglos por punteros las cosas son distintas.

Por empezar no estaría mal que nos aportes la declaración de dicha DLL o al menos la de las funciones de interés para conocer a que nos enfrentamos y luego en base a esto ya ver de que manera declararlo en Delphi.

Saludos,
  • 0

#8 Flack

Flack

    Newbie

  • Miembros
  • Pip
  • 5 mensajes

Escrito 04 febrero 2014 - 12:29

En la DLL hecha en C++ tengo como declaración de variable:



delphi
  1. double **a; 
  2. int  *IPOSV, *IZROV;
  3. int  i,j,ICASE,N,M,M1,M2,M3;



y çla función usada es:
 


delphi
  1. void simplx(double **a,int m,int n,int m1,int m2,int m3,int *icase,int *izrov, int *iposv)  {
  2. }



En delphi estoy declarando de la siguiente forma:



delphi
  1. matriz = array of array of double;
  2. Pmatriz = ^matriz;
  3. PPmatriz = ^Pmatriz;
  4. vetor = array of integer;
  5. vetor1 = array of integer;
  6. Pinteger = ^integer; 
  7. Pvetor = ^vetor;   
  8. Pvetor1 = ^vetor1; 



y intento limpiar la matriz de puntero de puntero asi:



delphi
  1.   for i := 1 to coluna do
  2.     begin
  3.       for j := 1 to linha do
  4.       begin
  5.       a^[j,i]:= 0;
  6.       end;
  7.     end;



pero obtengo un access violation.


  • 0

#9 Sergio

Sergio

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.092 mensajes
  • LocationMurcia, España

Escrito 04 febrero 2014 - 02:31

Pues me temo que no vas a poder hacerlo así de "sencillo", una matriz de float no es un tipo de dato standard para win32, eso quiere decir que cada lenguaje, y dentro de este incluso cada versión, puede almacenarlo en memoria de una forma diferente, por lo que usar matrices en el lado delphi casi seguro te dará errores del estilo.

Tienes la suerte de que el float si es un tipo win32, y de poder saber como se almacena la matriz en C++, que supongo que es poniendo cada float uno al lado del otro primero una fila y luego otra, con lo que si en delphi usas un puntero a float, puedes ir sumandole 1 y recorriendo la matriz linealmente (en delphi sumas 1 al puntero, no sizeof(float)), y si no te funciona, investiga como se almacenan en C++ esas matrices en memoria porque es la clave.


  • 0

#10 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 04 febrero 2014 - 04:09

Pues me temo que no vas a poder hacerlo así de "sencillo", una matriz de float no es un tipo de dato standard para win32, eso quiere decir que cada lenguaje, y dentro de este incluso cada versión, puede almacenarlo en memoria de una forma diferente, por lo que usar matrices en el lado delphi casi seguro te dará errores del estilo.

Tienes la suerte de que el float si es un tipo win32, y de poder saber como se almacena la matriz en C++, que supongo que es poniendo cada float uno al lado del otro primero una fila y luego otra, con lo que si en delphi usas un puntero a float, puedes ir sumandole 1 y recorriendo la matriz linealmente (en delphi sumas 1 al puntero, no sizeof(float)), y si no te funciona, investiga como se almacenan en C++ esas matrices en memoria porque es la clave.


Pues, en Delphi manejar matrices con punteros no es tan simple. En el enlace que puso Escafrandra lleva a un hilo que yo inicié hace un tiempo en donde me planteé justamente hacerlo por la manera dura. En dicho se barajan alternativas de más bajo nivel que la que ofrece SetLength que son GetMem y la api VirtualAlloc. Con ambas se requiere un tratamiento muy particular de uso de punteros, al menos en Delphi.

Claro está, esto no invalida tu punto: Cada lenguaje tiene su forma de encarar a las matrices, o más general: la forma de reservar memoria y acceder a ésta.

Saludos,
  • 0

#11 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 04 febrero 2014 - 05:01

En la DLL hecha en C++ tengo como declaración de variable:



delphi
  1. double **a; 
  2. int  *IPOSV, *IZROV;
  3. int  i,j,ICASE,N,M,M1,M2,M3;



y çla función usada es:
 


delphi
  1. void simplx(double **a,int m,int n,int m1,int m2,int m3,int *icase,int *izrov, int *iposv)  {
  2. }



En C/C++ un puntero a un puntero no tiene porqué ser una matriz (de matrices), por lo tanto lo primero que precisas saber es si realmente esa función usa una matriz o simplemente trata de pasar por referencia un puntero (para que la función le asigne una matriz simple, por ejemplo...)

En el caso de que realmente requiera una matriz de matrices, te la construyes estilo C, es decir una matriz de n punteros que cada uno apunta a una matriz. ¿Como se hace esto?, Fácil.  Reservas espacio de memoria para n elementos de tamaño puntero (32 bits o 64 según tu compilador) y en un bucle vas asignando a cada puntero otro espacio de memoria de tamaño n*sizeof(double).

Puedes usar un truco, si no te apetece lo anterior. Teniendo en cuenta que en C una matriz está representada por un puntero al primer elemento, creas una matriz de punteros estilo delphi y al puntero a puntero le asignas el puntero al primer elemento: @Elemento[0]. Esta idea sería la misma para asignar las matrices de double en un bucle.


Saludos.
  • 0

#12 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 04 febrero 2014 - 07:21

En el caso de que realmente requiera una matriz de matrices, te la construyes estilo C, es decir una matriz de n punteros que cada uno apunta a una matriz. ¿Como se hace esto?, Fácil.  Reservas espacio de memoria para n elementos de tamaño puntero (32 bits o 64 según tu compilador) y en un bucle vas asignando a cada puntero otro espacio de memoria de tamaño n*sizeof(double).

Puedes usar un truco, si no te apetece lo anterior. Teniendo en cuenta que en C una matriz está representada por un puntero al primer elemento, creas una matriz de punteros estilo delphi y al puntero a puntero le asignas el puntero al primer elemento: @Elemento[0]. Esta idea sería la misma para asignar las matrices de double en un bucle.


Saludos.

Esto que dices entonces es diferente al problema que hemos tratado en mi hilo. ¿Podrías dar una muestra de código para ver como sería (cuando tengas un tiempo libre)? Me interesa a mi también el tema, de paso aprendo algo nuevo.

Saludos,
  • 0

#13 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 04 febrero 2014 - 07:23

Ampliando el tema, si usas matrices dinámicas puedes simplificar el asunto de los punteros, pues éstas representan en si mismas un puntero al primer elemento del array. En este caso tienes la opción de hacer un casting o redeclalar la función en C.

El casting lo harías así:


delphi
  1. type PPdouble = ^Pdouble;
  2.  
  3. var
  4.   A: array of array of double;
  5. begin
  6. ............................
  7.   simplx(PPdouble(A),....{resto de parámetros});
  8. end;



Si usas arrays estáticos deberás usar punteros a los primeros elementos del array.


Saludos.







  • 0

#14 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 04 febrero 2014 - 07:35

Esto que dices entonces es diferente al problema que hemos tratado en mi hilo. ¿Podrías dar una muestra de código para ver como sería (cuando tengas un tiempo libre)? Me interesa a mi también el tema, de paso aprendo algo nuevo.


El lio de los punteros, a ver si con este ejemplo se entiende:


delphi
  1. type PPdouble = ^Pdouble;
  2.  
  3. var
  4.   A: array [0..2] of Pdouble;
  5.   B: array [0..2] of double;
  6.   C: array [0..2] of double;
  7.   D: array [0..2] of double;
  8. begin
  9.   A[0]:= @B[0];
  10.   A[1]:= @C[0];
  11.   A[2]:= @D[0];
  12.  
  13. // @A[0] seria un puntero a un puntero double pudiendo hacer PPDouble(@A[0]) y pasarlo a la función
  14.  
  15. end;




Para mi ya es muy tarde... voy a la cama. :s

Saludos.
  • 0

#15 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 04 febrero 2014 - 07:39

Ampliando el tema, si usas matrices dinámicas puedes simplificar el asunto de los punteros, pues éstas representan en si mismas un puntero al primer elemento del array. En este caso tienes la opción de hacer un casting o redeclalar la función en C.

El casting lo harías así:


delphi
  1. type PPdouble = ^Pdouble;
  2.  
  3. var
  4.   A: array of array of double;
  5. begin
  6. ............................
  7.   simplx(PPdouble(A),....{resto de parámetros});
  8. end;



Si usas arrays estáticos deberás usar punteros a los primeros elementos del array.


Saludos.







O sea que así como está declarado en C el doble puntero:



delphi
  1. double **a;



Y siendo una hipotética función Simplx "importada" desde una DLL escrita en C como la del ejemplo, ¿es posible usar desde Delphi asi como si nada, en toda la vida?

Es decir que si yo tengo:



delphi
  1. type
  2. Matrix = array of array of Double;
  3. var
  4. a: Matrix;
  5. i,j: integer;
  6. begin
  7.   SetLength(a, 10, 20);
  8.   for i := Low(a) to High(a) do
  9.     for j := Low(a[i]) to High(a[i]) do
  10.       a[i, j] := Random;
  11. end;



¿Puedo mandar esta matriz hacia la DLL sin problemas a que la ejecute como si fuera una matriz declarada en C?

¿Entonces como o en que se diferencia lo que hemos estado discutiendo en mi hilo? Porque ya estoy perdido.  :

Saludos,

  • 0

#16 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 05 febrero 2014 - 01:25

O sea que así como está declarado en C el doble puntero:



delphi
  1. double **a;



Y siendo una hipotética función Simplx "importada" desde una DLL escrita en C como la del ejemplo, ¿es posible usar desde Delphi asi como si nada, en toda la vida?

Es decir que si yo tengo:



delphi
  1. type
  2. Matrix = array of array of Double;
  3. var
  4. a: Matrix;
  5. i,j: integer;
  6. begin
  7.   SetLength(a, 10, 20);
  8.   for i := Low(a) to High(a) do
  9.     for j := Low(a[i]) to High(a[i]) do
  10.       a[i, j] := Random;
  11. end;



¿Puedo mandar esta matriz hacia la DLL sin problemas a que la ejecute como si fuera una matriz declarada en C?

¿Entonces como o en que se diferencia lo que hemos estado discutiendo en mi hilo? Porque ya estoy perdido.  :

Saludos,


Cierto es así como trabaja C. Delphi no es tan distinto cuando se trata de arrays dinámicos, el nombre del array representa un puntero al primer elemento del array. Tambien funciona su uso explicito, por supuesto.

Recuerdo que en aquel hilo discutíamos como usar las matrices con punteros, más concretamente la asignación de memoria. Pero, como recordarás, una vez asignada la memoria podías usarla como una matriz normal. Recuerda este código:


delphi
  1.   Matrix2:= VirtualAlloc(nil, SizeOf(Pointer) * Rows + Rows * Cols * SizeOf(Double), MEM_COMMIT, PAGE_READWRITE);
  2.   for k := 0 to Rows - 1 do
  3.     PPointer(Cardinal(Matrix2) + k*SizeOf(Pointer))^:= Pointer(Cardinal(Matrix2)+SizeOf(Pointer)* Rows + Cols * SizeOf(double)* k);
  4.  
  5.   for i := 0 to Rows-1 do
  6.     for j := 0 to Cols-1 do
  7.       TMatrix(Matrix2)[i][j] := i + j;
  8.  
  9.   VirtualFree(Matrix2, 0, MEM_RELEASE);



Verás que reservamos memoria para Rows punteros, y acontinuación para el resto de matrices de siguiente nivel; todo ello de golpe. La filosofía es un puntero que apunta a una matriz de punteros los cuales, a su vez, apuntan a otra matriz cada uno. La velocidad se conseguía por la asignación en bloque y con la API VirtualAlloc. Discutíamos, tambien sobre el uso de artimética de punteros para alcanzar un elemento dado.

En C, no tiene porqué estar todo el bloque consecutivo, cada array de segundo nivel puede ser reservado (su espacio de memoria) en cualquier momento y no consecutivo, lo importante es la estructura de punteros.

Como ves, la filosofía es la misma, pero distintos puntos de vista.


Saludos.
  • 0

#17 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 05 febrero 2014 - 01:30

Lo único que se es que C me rompe la cabeza.  :D
Menos mal que con Object Pascal las cosas me son menos rebuscadas.

Se dice que uno no se hace desarrollador hasta que enfrente a los punteros y salga vivo. Y yo que me conformé con los prácticos de clases de Estructuras de Datos y lenguajes (en lo que respecta a punteros). De allí al día de hoy, si tengo la posibilidad de evitarlos, lo hago.  :(

Saludos,
  • 0

#18 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 05 febrero 2014 - 03:13

Lo único que se es que C me rompe la cabeza.  :D
Menos mal que con Object Pascal las cosas me son menos rebuscadas.


En realidad las cosas en C no son tan rebuscadas, al contrario, C facilita mucho determinadas tareas y el uso de punteros. La cosa parece mas rebuscada cuando se mira desde delphi, pero sabiendo bien donde se quiere llegar todo es salvable y delphi es muy potente en ese sentido, aunque hay que dar mas vueltas a la sintaxis cuando trabajamos con punteros.

No es necesario el uso de punteros para la mayoría de los casos de modo que un desarrollador no tiene porqué ser un experto en esa materia.


Saludos.
  • 0

#19 Flack

Flack

    Newbie

  • Miembros
  • Pip
  • 5 mensajes

Escrito 10 febrero 2014 - 09:14

Hola todos,
Soy iniciante en esto y no concigo entender muy bien sus respuesta :(.

El programa es:



delphi
  1. type
  2.   matriz = array of array of double; 
  3.   Pmatriz = ^matriz;
  4.   PPmatriz = ^Pmatriz;
  5.  
  6. var
  7.   a : PPmatriz;
  8.  
  9. procedure xxx (var a:PPmatriz); cdecl; external 'Matrizdinamica.dll' name '?simplx@@YAXPAPANHHHHHPAH11@Z';
  10. begin
  11.   linha:= 3;
  12.   coluna:= 5;
  13.   GetMem (a, linha*coluna *Sizeof(double));
  14.   for i := 1 to coluna do
  15.   begin
  16.     for j := 1 to linha do
  17.     begin
  18.       a^[j,i]:= 4;
  19.     end;
  20.   end;
  21. end;



No he conseguido encontrar el problema, tengo un error de access violation, no se si esta escrito correctamente o no.........., solo deseo usar una matriz ponteiro de ponteiro (en C++ **matriz), que viene de una dll de C++ y que todos sus elementos sean igual a 4

  • 0

#20 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 10 febrero 2014 - 07:07

Escribe la declaración de la función tal y como está en la dll en C, o sube el archivo cabecera (.h) de esa dll.

Saludos.
  • 0




IP.Board spam blocked by CleanTalk.