4.3.8 Matrices como argumento de funciones
§1 Observación
No confundir el paso de una matriz en su conjunto (multidimensional o no) como argumento de una función, con el paso de un elemento de una matriz. Ejemplo:
int dias[2][12] = {
{31,28,31,30,31,30,31,31,30,31,30,31},
{31,29,31,30,31,30,31,31,30,31,30,31} };
....
x = fun1(dias, f, c, d, e); // paso de matriz
z = fun2(dias[f][c], d, e); // paso de elemento
§2 Sinopsis
Cuando hay que pasar una matriz bidimensional como argumento a una función, la declaración de parámetros formales de esta debe incluir el número de columnas, ya que la función receptora debe conoce la estructura interna de la matriz, para poder para acceder a sus elementos, y esto solo es posible informándole de su tipo y dimensiones. En el caso que nos ocupa las dimensiones son dos, por lo que la definición de la función llamada sería algo así:
func (int dias[2][12]) {...} // §2a
Observe que en la expresión anterior está incluida toda la información necesaria: número de filas, número de columnas
y tamaño de cada elemento (un int). Desde luego la función receptora necesita conocer también la dirección de inicio
del almacenamiento, pero ya hemos señalado (
4.3.2) que "el identificador de una matriz puede ser utilizado como un
puntero a su primer elemento", con lo que si mentalmente sustituimos dias por un puntero al número 31 (primer
elemento) de la primera matriz, la información pasada es completa.
§3 Ya se ha señalado que C++ no contiene operadores para manejar matrices como una
sola unidad ( 4.3.1). Al
contrario de lo que ocurre en otros lenguajes (por ejemplo Java), en C++ es responsabilidad del programador no salirse del
ámbito de la matriz al acceder a sus elementos, lo que una vez aceptado, nos conduce a que en realidad es innecesario
conocer la primera dimensión. En efecto, en nuestro caso, el primer elemento (primera sub-matriz), es accedido directamente
mediante el puntero dias; su tamaño ya lo conocemos (12 int), y con esta información es suficiente para acceder
a cualquier otro elemento n. Solo es necesario desplazar el puntero los las posiciones de memoria correspondientes.
La conclusión anterior estaba ya implícitamente establecida en
( 4.3.6),
donde hemos visto que, en una matriz bidimensional m[F][C], la posición Pf,c respecto
del comienzo del elemento m[f][c] viene determinado por:
Pf,c = ( C * f ) + c
expresión que es independiente del valor F (número de filas). Como consecuencia, la definición §2a
podría ser del tipo:
func (int dias[][12]) {...} // §3a
El primer paréntesis vacío es necesario para colocar el segundo, que es el que interesa. La expresión es
conceptualmente equivalente (
4.3.2) a:
func (int (*dias)[12]) {...} // §3b
que indica explícitamente el hecho de que el parámetro es un puntero-a-matriz de 12 int.
§4 Comprobamos la veracidad de lo expuesto a un sencillo ejemplo:
#include <stdio.h>
void escribe(int a[][12], int x, int y); // prototipo
void escribo(int (*a)[12], int x, int y); // prototipo
void main () { // =============
int dias[2][12] = {
{ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12},
{13,14,15,16,17,18,19,20,21,22,23,24}
};
escribe(dias, 1, 3);
escribe(dias, 0, 7);
escribo(dias, 1, 3);
escribo(dias, 0, 7);
}
void escribe(int a[][12], int f, int c) { // definición
printf("Valor [%2i,%2i] = %3i\n", f, c, a[f][c]);
}
void escribo(int (*a)[12], int f, int c) { // definición
printf("Valor [%2i,%2i] = %3i\n", f, c, a[f][c]);
}
Salida:
Valor [ 1, 3] = 16
Valor [ 0, 7] = 8
Valor [ 1, 3] = 16
Valor [ 0, 7] = 8