Está en la página 1de 4

Punteros a matrices

Asumiendo que los elementos de una matriz se almacenan de forma contigua y


que z es el tamaño en bytes de un elemento tipo X, el desplazamiento d en bytes
respecto del comienzo, del elemento a[i] de una matriz tipo X a[n];, viene
determinado por:
Desplazamiento (en bytes) d = posición i · tamaño del elemento z
Siendo el tamaño del elemento: z = sizeof (tipo X).
Sin embargo, hemos visto que la aritmética de punteros incluye automáticamente
el tamaño del elemento. Por tanto, para manejar las matrices a través de punteros
no es preciso referirse a las posiciones absolutas d de sus elementos (en bytes
desde el comienzo de la matriz), sino en unidades tipo X. Es decir, a efectos de los
punteros, la posición pi (respecto al comienzo) del elemento a[i] es simplemente pi
= i.
Al primer elemento, a[0], de una matriz de dimensión m le corresponde la posición
0 y al último la posición m-1. El significado es que para alcanzar el primer
elemento desde el principio el desplazamiento es cero, para el segundo el
desplazamiento es un elemento, dos para el tercero, ... y m-1 para el último.

Podríamos decir que el nemónico de una matriz C++ encierra una dualidad. En
momentos puede ser considerado como representante de una matriz. Por ejemplo,
cuando lo utilizamos con la notación de subíndices o en el operador sizeof. En
otros casos adquiere la personalidad de puntero. Por ejemplo, cuando utilizamos
con él el álgebra de punteros (en cierta forma, me recuerda la famosa dualidad
onda-partícula de la luz que estudiamos en bachiller).

Esta dualidad hace que a efectos prácticos (salvo las excepciones ya


comentadas), el identificador de una matriz sea sinónimo de la dirección de su
primer elemento; de modo que si m es una matriz de elementos tipo X y pm un
puntero-a-tipo X, la asignación pm = &m[0]; puede también ser expresada
como pm = m;, o lo que es lo mismo, para la mayoría de los casos prácticos se
puede establecer que:

 pm == &m[0] == m     

Es decir:

 m == &m[0]  ↔  *m == m[0]     


En el siguiente ejemplo se muestra como el nombre de la matriz puede ser tomado
directamente como sinónimo de puntero al primer elemento.

int a[5] = {1,2,3,4,5};


printf("Posicion 0 = %1i\n", *a);
printf("Posicion 3 = %1i\n", *(a+3));

salida:

Posicion 0 = 1
Posicion 3 = 4

  Como vemos a continuación, es lo mismo pasar como argumento de una función:

1. Meramente el nombre de la matriz


2. La dirección del primer elemento
3. Un puntero al primer elemento

Las tres alternativas producen el mismo resultado.

char a[11] = "Hola mundo",


char* ptr = &a[0];
char* s = "Hola mundo";
printf("%s\n", a);      // 1
printf("%s\n", &a[0]);  // 2
printf("%s\n", ptr);    // 3
printf("%s\n", s);      // 3

Las cuatro funciones producen la misma salida, en todas ellas printf imprime


desde la primera posición hasta alcanzar el primer nulo, que es interpretado como
fin de cadena. El último es interpretado como no imprimible y automáticamente
descartado.

Obsérvese que en la primera línea hemos hecho deliberadamente la dimensión de


la matriz mayor que la cadena en 1 elemento para que el compilador incluya al
final el carácter nulo. En cambio, en la definición de constantes de cadena (tercera
línea) el compilador incluye por su cuenta el carácter de final

En el ejemplo siguiente, además de demostrarse lo anterior, se comprueba como


la función func supone que el argumento recibido es un puntero, y como tal lo trata
en printf().

#include <stdio.h>
void func(char* ptr);   // prototipo
 
void main() {
   char a[5] = "AEIOU", *ptr = &a[0];
   func(a);              // Las tres
   func(ptr);           // llamadas son
   func(&a[0]);         // equivalentes
}
void func(char* arr) {  // definición
  int i;
  for (i=0; i<5; i++) {
      printf("arr[%1i] =%5.0d =%2c\n", i, *arr, *arr);
     arr++;
  }
  return;
}

Salida para las tres funciones:

arr[0] = 65 = A
arr[1] = 69 = E
arr[2] = 73 = I
arr[3] = 79 = O
arr[4] = 85 = U

La dualidad matriz ↔ puntero también se pone de manifiesto en este sencillo


ejemplo:

#include <iostream.h>

void fun(char*, int);        // L.3

int main() {                 // ============


  char* arr = new char[5];   // L.5
  fun(arr, 5);               // L.6
  delete[] arr; return 0;
}

void fun (char a[], int x) {      // L.9


  a[x] = static_cast<char>(x+65); // L.10
  cout << a[x] << endl;
}

Aparentemente la declaración de fun en su prototipo de L.3 y su definición en L.9


no coinciden, a pesar de lo cual, no se obtiene ninguna protesta por parte del
compilador. Así mismo, en L.5 se define arr como puntero-a-char y se pasa (L.6) a
fun como argumento, aunque es aceptada por esta última como matriz de
caracteres (char a[]), y utilizada como tal con la correspondiente notación de
subíndices en L.10 y L.11 sin que exista tampoco protesta por parte del
compilador.
Bibliografia
http://www.uco.es/grupos/eatco/informatica/metodologia/mtptema13.pdf
https://archive.wunk.me/es/programacion-en-c-matrices-con-punteros/
http://weblidi.info.unlp.edu.ar/catedras/TallerLeng1/04_Punteros.pdf

También podría gustarte