punteros dobles y matrices en DELPHI
#1
Escrito 03 febrero 2014 - 12:33
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
#2
Escrito 03 febrero 2014 - 01:49
type PDWORD = ^DWORD; type PPDWORD = ^PDWORD; //.................... var uno: PPDWORD; dos: PDWORD; tres: DWORD; begin tres:= 1; dos:= @tres; uno:= @dos; (uno^)^:=3; end;
Pero en delphi las matrices no son como en C. Puedes ver una discusión de este tema aquí.
Saludos.
#3
Escrito 04 febrero 2014 - 08:21
#4
Escrito 04 febrero 2014 - 09:11
var a: array of array of double; begin // Dimensiono la matriz: SetLength(a, 10); // Cada sub-elemento es otra matriz de longitud variable for i:= Low(a) to High(a) do SetLength(a[i], 20); // nota: Puedo añadir huecos si los necesito: SetLength(a[0], 21); // Para acceder a un elemento, solo haces esto: Valor:= a[i, j];
Esto es con matrices de largo variable, si fuesen fijas mas sencillo:
var a: array [0..9] of array [0..19] of double; begin // Para acceder a un elemento, solo haces esto: Valor:= a[i, j];
#5
Escrito 04 febrero 2014 - 09:18
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:
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:
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. Aunque para el caso se me hace más elegante un tipo record:
type Cuaternion = record r, i, j, k: Double; end;
Siendo r el componente real e i, j, y k los componentes imaginarios. Y hasta allí llega mis conocimientos de Física
Saludos,
#6
Escrito 04 febrero 2014 - 11:50
(a^[i,j])^ := 3; ????
#7
Escrito 04 febrero 2014 - 12:10
Hola Flack,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; ????
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,
#8
Escrito 04 febrero 2014 - 12:29
double **a; int *IPOSV, *IZROV; int i,j,ICASE,N,M,M1,M2,M3;
y çla función usada es:
void simplx(double **a,int m,int n,int m1,int m2,int m3,int *icase,int *izrov, int *iposv) { }
En delphi estoy declarando de la siguiente forma:
matriz = array of array of double; Pmatriz = ^matriz; PPmatriz = ^Pmatriz; vetor = array of integer; vetor1 = array of integer; Pinteger = ^integer; Pvetor = ^vetor; Pvetor1 = ^vetor1;
y intento limpiar la matriz de puntero de puntero asi:
for i := 1 to coluna do begin for j := 1 to linha do begin a^[j,i]:= 0; end; end;
pero obtengo un access violation.
#9
Escrito 04 febrero 2014 - 02:31
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.
#10
Escrito 04 febrero 2014 - 04:09
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.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.
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,
#11
Escrito 04 febrero 2014 - 05:01
En la DLL hecha en C++ tengo como declaración de variable:
delphi
double **a; int *IPOSV, *IZROV; int i,j,ICASE,N,M,M1,M2,M3;
y çla función usada es:
delphi
void simplx(double **a,int m,int n,int m1,int m2,int m3,int *icase,int *izrov, int *iposv) { }
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.
#12
Escrito 04 febrero 2014 - 07:21
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.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.
Saludos,
#13
Escrito 04 febrero 2014 - 07:23
El casting lo harías así:
type PPdouble = ^Pdouble; var A: array of array of double; begin ............................ simplx(PPdouble(A),....{resto de parámetros}); end;
Si usas arrays estáticos deberás usar punteros a los primeros elementos del array.
Saludos.
#14
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:
type PPdouble = ^Pdouble; var A: array [0..2] of Pdouble; B: array [0..2] of double; C: array [0..2] of double; D: array [0..2] of double; begin A[0]:= @B[0]; A[1]:= @C[0]; A[2]:= @D[0]; // @A[0] seria un puntero a un puntero double pudiendo hacer PPDouble(@A[0]) y pasarlo a la función end;
Para mi ya es muy tarde... voy a la cama.
Saludos.
#15
Escrito 04 febrero 2014 - 07:39
O sea que así como está declarado en C el doble puntero: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
type PPdouble = ^Pdouble; var A: array of array of double; begin ............................ simplx(PPdouble(A),....{resto de parámetros}); end;
Si usas arrays estáticos deberás usar punteros a los primeros elementos del array.
Saludos.
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:
type Matrix = array of array of Double; var a: Matrix; i,j: integer; begin SetLength(a, 10, 20); for i := Low(a) to High(a) do for j := Low(a[i]) to High(a[i]) do a[i, j] := Random; 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,
#16
Escrito 05 febrero 2014 - 01:25
O sea que así como está declarado en C el doble puntero:
delphi
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
type Matrix = array of array of Double; var a: Matrix; i,j: integer; begin SetLength(a, 10, 20); for i := Low(a) to High(a) do for j := Low(a[i]) to High(a[i]) do a[i, j] := Random; 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:
Matrix2:= VirtualAlloc(nil, SizeOf(Pointer) * Rows + Rows * Cols * SizeOf(Double), MEM_COMMIT, PAGE_READWRITE); for k := 0 to Rows - 1 do PPointer(Cardinal(Matrix2) + k*SizeOf(Pointer))^:= Pointer(Cardinal(Matrix2)+SizeOf(Pointer)* Rows + Cols * SizeOf(double)* k); for i := 0 to Rows-1 do for j := 0 to Cols-1 do TMatrix(Matrix2)[i][j] := i + j; 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.
#17
Escrito 05 febrero 2014 - 01:30
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,
#18
Escrito 05 febrero 2014 - 03:13
Lo único que se es que C me rompe la cabeza.
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.
#19
Escrito 10 febrero 2014 - 09:14
Soy iniciante en esto y no concigo entender muy bien sus respuesta .
El programa es:
type matriz = array of array of double; Pmatriz = ^matriz; PPmatriz = ^Pmatriz; var a : PPmatriz; procedure xxx (var a:PPmatriz); cdecl; external 'Matrizdinamica.dll' name '?simplx@@YAXPAPANHHHHHPAH11@Z'; begin linha:= 3; coluna:= 5; GetMem (a, linha*coluna *Sizeof(double)); for i := 1 to coluna do begin for j := 1 to linha do begin a^[j,i]:= 4; end; end; 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
#20
Escrito 10 febrero 2014 - 07:07
Saludos.