En C++ (y seguro que en C también) los arreglos multi-dimensionales están alojados en memoria de manera anexa, así que la conversión de varias dimensiones a una dimensión es posible y segura.
No he encontrado la sección del estándar de C++ que indica mi afirmación anterior, pero queda implícitamente confirmado en la siguiente nota (la traducción es mía):
8.3.4 Arreglos
...
- Se sigue una norma consistente en los arreglos multidimensionales. Si
E
es un arreglo de n-dimensiones de rango i × j × ... × k
, entonces E
usado en una expresión sujeta a la conversión arreglo-a-puntero (4.2) será convertido a un puntero a un arreglo de (n-1) dimensiones con un rango j × ... × k
. Si el operador *
es aplicado a este puntero de manera implícita o explícita como resultado de sub-indizar, el resultado es un puntero al arreglo de (n-1) dimensiones, que a su vez será convertido inmediatamente a puntero.
[Ejemplo: consideremos
int x[3][5];
Aquí x
es un arreglo de 3 × 5
enteros. Cuando x
aparecie en una expresión, es convertido a puntero a (los tres primeros) arreglo de enteros de cinco elementos. En la expresión x[i]
que es equivalente a *(x+i)
, x
es convertido en primer lugar a puntero tal y como se describió; entonces x+i
es convertido al tipo de x
, que implica multiplicar i
por la longitud del objeto al que el puntero apunta, específicamente cinco objetos de tipo entero. El resultado se suma y las indirecciones se aplican para devolver un arreglo (de cinco enteros), que a su vez es convertido a un puntero al primero de los enteros. Si hay otra dimensión el mismo proceso se aplica de nuevo; en esta coasión el resultado es un entero. - fin del ejemplo]
Tal y como se describen las operaciones para acceder a los elementos de un arreglo multi-dimensional, se entiende que toda la memoria es anexa y en consecuencia un arreglo multidimensional puede ser tratado como uno de una sola dimensión.
Pasando arreglos a funciones.
Al ejecutar el programa, el array pasa por la función y sale como si nada, no veo que modifique ningún valor en ningún momento
Has cometido un error típico de principiante en el mundo de los punteros. Cuando una función recibe un puntero, lo que la función está recibiendo es una copia del puntero, así que los cambios se aplicarán sobre la copia, no sobre el original. Para modificar el puntero original debes pasar un puntero al puntero o una referencia al mismo:
void squared_map_creation_pointer_2_pointer(int** map, int length)
{
int counter = 0;
while (counter < length*length)
{
(*map)[counter] = counter;
counter++;
}
}
En la versión puntero-a-puntero, necesitamos des-referenciar el puntero map
(usar el operador unario *
) una vez para acceder al contenido original (no la copia), de ahí que se use la instrucción (*map)[counter] = counter;
. Yo personalmente prefiero la versión con referencia:
void squared_map_creation_reference_2_pointer(int*& map, int length)
{
int counter = 0;
while (counter < length*length)
{
map[counter] = counter;
counter++;
}
}
En este caso no hay que des-referenciar el puntero, ya que tenemos una referencia al puntero original. Puedes usar estas funciones de la siguiente manera:
int main()
{
int datos[10][10] {{}};
int *begin = *datos;
// La llamada puntero-a-puntero necesita obtener la direccion
// del puntero al inicio del arreglo.
squared_map_creation_pointer_2_pointer(&begin, 10);
// En la llamada referencia-a-puntero se puede pasar el puntero
// directamente, sin operaciones adicionales.
squared_map_creation_reference_2_pointer(begin, 10);
return 0;
}
Alternativa con plantillas.
Puedes usar plantillas de C++ para el mismo propósito:
template <std::size_t LENGTH>
void squared_map_creation(int (&map)[LENGTH][LENGTH])
{
std::size_t counter = 0;
int* begin = *map;
while (counter < LENGTH*LENGTH)
{
begin[counter] = counter;
counter++;
}
}
En este caso la función puede ser llamada así:
int main()
{
int datos[10][10] {{}};
squared_map_creation(datos);
return 0;
}
La función recibe una referencia a un arreglo de dos dimensiones, el tipo del parámetro map
es int (&)[10][10]
que como ya se ha mencionado es de tipo referencia (&
) a arreglo de dos dimensiones, ambas de 10 elementos ([10][10]
) de enteros (int
); dado que es una referencia no se necesitan operadores adicionales para pasar el arreglo a la función; la plantilla se encarga de deducir el tamaño del arreglo y por eso tampoco es necesario pasar el tamaño a la función.