Tipo_base nombre_lista[DIMENSION]; Tipo_base * puntero = nombre_lista;El nombre el elemento i-ésimo de la lista es
nombre_lista[i
] o también
*(nombre_lista+i)
o tambien
*(puntero+i)
nombre_lista
o
puntero
, y el desplazamiento lo indica
i
(concretamente, el desplazamiento es
i*sizeof(Tipo_base)
). Estas operaciones, insistimos, tienen su contrapartida directa en lenguaje máquina y son muy eficientes.Tipo_base *puntero;bastan, según lo visto, para recorrer listas, tablas o matrices de cualquier tipo de dimensiones, empleando un único índice. Esto es suficiente en muchas ocasiones, pero puede resultar más cómodo emplear la sintaxis matricial habitual para recorrer tablas, tarugos o matrices de más dimensiones. C ofrece la posibilidad de crear punteros que tengan como tipo base filas completas, tablas completas, tarugos completos, etc. Estos punteros se pueden emplear con dos índices (para recorrer tablas), con tres punteros (para recorrer tarugos), con cuatro punteros (para recorrer teseractos), etc. Un ejemplo de esto son las siguientes declaraciones, en las que se construye un puntero de fila, otro de tabla y otro de tarugo:
Tipo_base (*p_fila)[NUMERO_DE_COLUMNAS]; Tipo_base (*p_tabla)[NUMERO_DE_FILAS][NUMERO_DE_COLUMNAS]; Tipo_base (*p_tarugo)[NUMERO_DE_CAPAS][NUMERO_DE_FILAS][NUMERO_DE_COLUMNAS];Los punteros construidos aquí (
p_fila
,
p_tabla
y
p_tarugo
) poseen las características siguientes:
p_fila
señala toda una fila formada por
NUMERO_DE_COLUMNAS
elementos de Tipo_base. Por tanto,
*p_fila
es toda una fila completa, formada por
NUMERO_DE_COLUMNAS
elementos, y
p_fila[i]
sería la (hipotética) i-ésima fila de una tabla formada por filas de
NUMERO_DE_COLUMNAS
columnas del tipo base. Como
p_fila[i]
es el nombre de una lista, se le puede aplicar un segundo índice,
j
, para acceder a elementos individuales de esa fila, en mediante expresiones de la forma
p_fila[i][j]
, que denotan la j-esima fila de la i-ésima columna. Para dar valor a
p_fila
se puede emplear una declaración como la siguiente:
Tipo_base tabla[NUMERO_DE_FILAS][NUMERO_DE_COLUMNAS]; Tipo_base (*p_fila)[NUMERO_DE_COLUMNAS]; p_fila = tabla;Esto tiene sentido porque
tabla
se interpreta como la dirección de su primer elemento, esto es, como
&tabla[0]
. Ahora bien,
tabla[0]
es una expresión con un sólo índice, luego alude a la primera fila (el índice del que se prescinde se quita "por la derecha"). Entonces
&tabla[0]
es la dirección de una fila formda por
NUMERO_DE_COLUMNAS
elementos, que es precisamente el tipo de
p_fila
. P
ara recorrer tablas se emplea un puntero de fila
.
NUMERO_DE_FILAS
filas, cada una de las cuales consta de
NUMERO_DE_COLUMNAS
columnas. Los elementos de esta tabla son del tipo
Tipo_base
. Entonces
*p_tabla
es toda una tabla y
p_tabla[i]
sería la (hipotética) i-ésima capa (tabla) de un tarugo cuyas capas tendrían
NUMERO_DE_FILAS
filas de
NUMERO_DE_COLUMNAS
columnas. Como
p_tabla[i]
es una tabla, se le puede añadir un segundo índice,
j
, para acceder a filas individuales de esa tabla. Entonces
p_tabla[i][j]
denota la j-ésima fila (completa) de la i-ésima tabla. Por último, al ser
p_tabla[i][j]
una fila... se le puede añadir un tercer índice,
k
, que denotará una columna dentro de esta fila. Esto es,
p_tabla[i][j][k]
denota la columna
k
de la fila
j
de la capa
i
de un (hipotético!) tarugo. Para dar valor a
p_tabla
se podría emplear una declaración como la siguiente:
Tipo_base (*p_tabla)[NUMERO_DE_FILAS][NUMERO_DE_COLUMNAS]; Tipo_base tarugo[NUMERO_DE_CAPAS][NUMERO_DE_FILAS][NUMERO_DE_COLUMNAS]; p_tabla = tarugo;Esto tiene sentido porque tarugo se interpreta como la dirección del primero de sus elementos, esto es,
&tarugo[0]
. Como en tarugo faltan dos índices, faltarán por la derecha. Entonces el índice restante denota la capa del tarugo, que es una tabla de dimensiones
NUMERO_DE_FILAS x NUMERO_DE_COLUMNAS
. Y
p_tabla
es precisamente un puntero de tabla de esas dimensiones así que todo encaja.
Para recorrer tarugos se emplea un puntero de tabla
.
p_tarugo
señala un tarugo completo, esto es, un objeto de
NUMERO_DE_CAPAS
capas cada una de las cuales es una tabla formada por
NUMERO_DE_FILAS
filas que poseen
NUMERO_DE_COLUMNAS
columnas de tipo
Tipo_base
. Entonces
*p_tarugo
es todo un tarugo y
p_tarugo[i]
denota el i-ésimo tarugo de un teseracto. Como tarugo que es, podemos añadir 1, 2 o 3 índices a
p_tarugo[i]
. Con un índice adicional,
p_tarugo[i][j]
, estaremos accedediendo a la capa
j
del iésimo tarugo del teseracto. Con dos índices adicionales,
p_tarugo[i][j][k]
, estaremos accediendo a la fila
k
de la capa
j
del tarugo
i
del teseracto. Con tres índices adicionales,
p_tarugo[i][j][k][l]
, estaremos accediendo a la columna
l
de la fila
k
de la capa
j
del i-ésimo tarugo del teseracto. Para dar valor a
p_tarugo
se podría emplear una declaración como la siguiente:
Tipo_base teseracto[NUMERO_DETARUGOS][NUMERO_DE_CAPAS][NUMERO_DE_FILAS][NUMERO_DE_COLUMNAS]; Tipo_base (*p_tarugo)[NUMERO_DE_CAPAS][NUMERO_DE_FILAS][NUMERO_DE_COLUMNAS]; p_tarugo = teseracto;Todo va bien porque estamos poniendo
p_tarugo = &teseracto[0]
y
teseracto[0]
denota el primer tarugo.
Para recorrer teseractos, se emplea un puntero de tarugo
. En general, para recorrer un objeto de N dimensiones, se emplea un puntero de objeto de N-1 dimensiones.
Tipo_base
) a los más grandes (filas, capas, tarugos). Entonces, ¿por qué se han creado los punteros de filas, capas, tarugos, etc.? La respuesta se encuentra en la asignación dinámica de memoria. Cuando se crea una variable dinámica, la única forma de acceder a ella es a través de un puntero: las variables dinámicas carecen de nombre. Entonces es preciso disponer de punteros del tipo adecuado,
que harán las veces de nombre de esas variables
. Todo esto se estudia en la
sección correspondiente
./* Este programa muestra el uso de listas (matrices monodimensionales) empleando punteros. */ #include <stdio.h> #include <stdlib.h> #include <time.h> #define DIMENSION 5 int main(void) { float lista[DIMENSION] = {1.0, 2.0, 3.0, 4.0, 5.0}; float * p = lista; int i; printf("Listas y punteros.\n\n"); for(i=0;i<DIMENSION;i++) printf("lista[%d] = %f\n", i,lista[i]); printf("\n\nDe otro modo:\n\n"); for(i=0;i<DIMENSION;i++) printf("*(%u + %d) = %f\n",(unsigned int)p,i,*(p+i)); printf("\n\nY de otro modo:\n\n"); for(i=0;i<DIMENSION;i++) printf("*(%u + %d) = %f\n",(unsigned int)p,i,p[i]); printf("\n\nY de otro modo:\n\n"); for(i=0;i<DIMENSION; i++) printf("*(%u + %d) = %f\n",(unsigned int)p,i,*p++); /* ¿Qué hace ++*p? */ printf("\n\nTerminación normal del programa.\n"); return 0; } /* RESULTADO Listas y punteros. lista[0] = 1.000000 lista[1] = 2.000000 lista[2] = 3.000000 lista[3] = 4.000000 lista[4] = 5.000000 Y de otro modo: *(97359480 + 0) = 1.000000 *(97359480 + 1) = 2.000000 *(97359480 + 2) = 3.000000 *(97359480 + 3) = 4.000000 *(97359480 + 4) = 5.000000 Y de otro modo: *(97359480 + 0) = 1.000000 *(97359484 + 1) = 2.000000 *(97359488 + 2) = 3.000000 *(97359492 + 3) = 4.000000 *(97359496 + 4) = 5.000000 Terminación normal del programa. */Comentarios .- La conclusión es la esperable. Podemos acceder a los elementos de la lista empleando la notación "algebraica" habitual, esto es, el nombre de la lista con un índice. También se puede emplear el puntero de lista con un índice que se va incrementando. Por último, se puede incrementar directamente el valor del puntero, mediante el operador ++. En todos los casos se calculan las mismas direcciones (de los elementos) y se obtienen, como era de esperar, los mismos valores. Obsérvese, por cierto, que el valor del puntero ha resultado modificado. ¡Cuando finaliza el bucle
for()
,
p
ya no apunta a un elemento de la lista!* Este programa muestra el uso de un único puntero para recorrer matrices bidimensionales. */ #include <stdio.h> #include <stdlib.h> #include <time.h> #define DIM_FILAS 5 #define DIM_COLS 5 #define Tipo_base float int main(void) { Tipo_base tabla[DIM_FILAS][DIM_COLS]; Tipo_base * puntero = tabla[0]; int i,j; printf ("Manejo de tablas con punteros\n\n"); /* Iniciación */ for(i=0;i<DIM_FILAS*DIM_COLS;i++) *(puntero + i) = i; /* Contenido de la matriz (método habitual) */ for(i=0; i < DIM_FILAS; i++) { for(j=0; j < DIM_COLS; j++) printf("%6.2f",tabla[i][j]); printf("\n"); } /* Direcciones de los elementos de la matriz (método habitual) */ for(i=0; i < DIM_FILAS; i++) { for(j=0; j < DIM_COLS; j++) printf("%u",(unsigned int)&tabla[i][j]); printf("\n"); } /* Recorrido análogo con 1 puntero */ printf("\n\nY de otro modo\n\n"); for(i=0; i < DIM_FILAS; i++) { for(j=0; j < DIM_COLS; j++) printf("%6.2f",*(puntero + i*DIM_COLS + j)); printf("\n"); } printf("\n\nY con menos código:\n\n"); for(i=0; i < DIM_FILAS*DIM_COLS; i++) { printf("%6.2f",*(puntero+i)); if( (i % DIM_COLS )==(DIM_COLS-1) )printf("\n"); } /* Con las modificaciones oportunas (añadiendo otro if() se puede tratar el caso de múltiples capas, o de múltiples tarugos. La condición es saltar de linea, o de capa, cuando el índice llega al número de columnas menos uno, o al de filas por columnas menos uno (para capas), o al de filas por columnas por capas menos uno (para tarugos). */ printf ("\n\nTerminación normal del programa.\n"); return 0; } /* RESULTADO Manejo de tablas con punteros 0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00 10.00 11.00 12.00 13.00 14.00 15.00 16.00 17.00 18.00 19.00 20.00 21.00 22.00 23.00 24.00 Y de otro modo 0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00 10.00 11.00 12.00 13.00 14.00 15.00 16.00 17.00 18.00 19.00 20.00 21.00 22.00 23.00 24.00 Y con menos código: 0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00 10.00 11.00 12.00 13.00 14.00 15.00 16.00 17.00 18.00 19.00 20.00 21.00 22.00 23.00 24.00 Terminación normal del programa. */
float
. Se pide construir un programa que muestre el valor máximo y mínimo de la lista, y que indique los índices de las posiciones en que se encuentran estos valores. Se supone que no hay valores repetidos.
float
. Se pide construir un programa que muestre el valor máximo y mínimo de la tabla, y que indique los índices de las posiciones en que se encuentran estos valores. Se supone que no hay valores repetidos.
float
(de dimensiones
CAPASxFILASxCOLUMNAS
). Se pide construir un programa que muestre el valor máximo y mínimo del tarugo, y que indique los índices de las posiciones en que se encuentran estos valores. Se supone que no hay valores repetidos.
float
.
struct
. La función tiene acceso a la definición del
struct
y conoce las dimensiones de la tabla.
struct
. La función sólo conoce el tamaño (
sizeof()
) del
struct
y las dimensiones de la tabla.
2x3x4
, formado por elementos de tipo
double
. Construir un programa que calcule las sumas de todas sus filas.