Como repaso, en el Capítulo 2 vimos que un puntero de tipo entero puede apuntar a un array de enteros, así:
int *ptr; ptr = &my_array[0]; /* el puntero apunta al primer elemento del array */Como vemos, el tipo de la variable puntero debe ser igual al tipo del primer elemento del array.
Además, podemos utilizar un puntero como parámetro formal de una función diseñada para manipular un array, es decir:
int array[3] = {1, 5, 7}; void a_func(int *p);Algunos programadores prefieren escribir el prototipo de esta función como:
void a_func(int p[]);para informar a cualquiera que utilice esta función de que está diseñada para manipular elementos de un array. En ambos casos lo que se pasa es el valor de un puntero apuntando al primer elemento del array, independientemente de la notación utilizada en el prototipo o definición de la función. Si se utiliza la notación de array no es necesario pasar la dimensión actual del array porque no estamos pasando el array completo, sólo estamos pasando una dirección a su primer elemento.
Volvamos al problema del array de dos dimensiones. Como vimos en el capítulo anterior, C interpreta un array de dos dimensiones como dos arrays de una dimensión. El primer elemento de un array de enteros de dos dimensiones es un array de enteros de una dimensión. Un puntero que apunte a un array de enteros de dos dimensiones debe ser un puntero de ese tipo de dato. Una forma de lograr esto es mediante el uso de la palabra clave "typedef", que asigna un nombre nuevo a un tipo de dato especificado. Por ejemplo:
typedef unsigned char byte;hace que el nombre byte sea el tipo unsigned char (caracter sin signo). Esto es:
byte b[10]; es un array de caracteres sin signo.Fíjate en la declaración de typedef: la palabra byte es sustituida por lo que sería el nombre de nuestro tipo caracter sin signo. Esto es, la regla para utilizar typedef es que el nuevo nombre para el tipo de dato es el nombre utilizado en la definición del tipo de dato. De esta forma:
typedef int Array[10];Array será un tipo de dato para un array de 10 enteros, es decir, Array mi_arr; declara mi_arr como un array de 10 enteros y Array arr2d[5]; declara arr2d como un array de 5 arrays de 10 enteros cada uno.
Fíjate también que Array *p1d; hace que p1d sea un puntero a un array de 10 enteros. Debido a que *p1d apunta al mismo tipo que arr2d, p1d puede apuntar a la dirección de un array de dos dimensiones arr2d como a un array de una dimensión de 10 enteros, es decir, es correcto tanto
p1d = &arr2d[0];como
p1d = arr2d;
Como el tipo de dato de nuestro puntero es un array de 10 enteros, podemos esperar que al incrementar p1d por 1 éste cambie su valor por 10*sizeof(int), y así es porque sizeof(*p1d) sería 20. Puedes probar esto escribiendo y ejecutando un pequeño y simple programa.
Ahora, utilizar typedef no hace las cosas más fáciles al programador ni más claras para el lector. Lo que necesitamos es declarar un puntero como p1d sin la palabra clave typedef. Resulta que esto se puede hacer y que
int (*p1d)[10];es la declaración apropiada, es decir, aquí p1d es un puntero a un array de 10 enteros como lo es con la declaración mediante el tipo Array. Ten en cuenta que esto es distinto de
int *p1d[10];pues esto hace que p1d sea el nombre de un array de 10 punteros de tipo int.