una - punteros c++
¿Cómo usar expresiones de puntero para acceder a elementos de una matriz bidimensional en C? (6)
La mesa
En C, las matrices 2D son series continuas de líneas (no como en Pascal).
Cuando organizamos una tabla de enteros con 4 filas y 5 columnas:
Alcanzando los elementos
Podemos llegar a los elementos con:
int element = table[row-1][column-1];
Pero también podemos hacer esto con el siguiente código:
int element = *(*(table+row-1)+column-1);
En estos ejemplos, row
y column
se cuentan a partir de 1, esa es la razón de -1.
En el siguiente código, puede probar que ambas técnicas son correctas. En este caso, contamos las filas y columnas desde 0.
Ejemplo
#include <stdio.h>
#include <stdlib.h>
#define HEIGHT 4
#define WIDTH 5
int main()
{
int table[HEIGHT][WIDTH] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
int row = 2;
int column = 2;
int a = *(*(table+row)+column);
printf("%d/n",a);//13
printf("%d/n",table[row][column]);//13
return 0;
}
Explicación
Esta es una aritmética de dos poces, por lo que la table
apunta a la primera fila y *table
apunta al primer elemento, si la dejaste de nuevo, **table
devolverá el valor del primer elemento. En el siguiente ejemplo, puede ver que *table
y la table
apuntan a la misma dirección de memoria.
printf("%d/n",table);//2293476
printf("%d/n",*table);//2293476
printf("%d/n",**table);//1
En la memoria, todas las filas de la tabla se siguen entre sí. Debido a que la table
apunta a la primera fila si agregamos el número de fila donde se encuentra el elemento necesario en la tabla, obtendremos un puntero que apunta a esa fila. En este caso *(table+row)
contendrá una dirección al primer elemento de la fila dada. Ahora solo tenemos que agregar el número de columna como *(table+row)+column
, y obtenemos la dirección del elemento en la fila y columna especificadas. Si desactivamos esto, obtenemos el valor exacto de este elemento.
Entonces, si contamos las filas y columnas desde cero, podemos obtener elementos de la tabla como este:
int element = *(*(table+row)+column);
En la memoria
Sé que para arreglos unidimensionales x=a[i]
es equivalente a x=*(a+i)
, pero ¿cómo puedo acceder a los elementos de una matriz bidimensional utilizando punteros?
Las respuestas anteriores ya se explicaron muy bien, solo enumeraría las expresiones de los punteros de acuerdo con mi comprensión, y las compararía con el formato arr [i] [j] .
Pointer expression of 2-D array: the array name itself is a pointer to first sub array, arr: will be pointer to first sub array, not the first element of first sub array, according to relationship of array & pointer, it also represent the array itself, arr+1: will be pointer to second sub array, not the second element of first sub array, *(arr+1): will be pointer to first element of second sub array, according to relationship of array & pointer, it also represent second sub array, same as arr[1], *(arr+1)+2: will be pointer to third element of second sub array, *(*(arr+1)+2): will get value of third element of second sub array, same as arr[1][2],
Similar a la matriz 2-D, la matriz múltiple D tiene una expresión similar.
Una forma práctica de acceder con un puntero.
typedef struct
{
int Array[13][2];
} t2DArray;
t2DArray TwoDArray =
{
{ {12,5},{4,8},{3,6},{7,9},{3,2},{3,3},{3,4},{3,5},{3,6},{3,7},{4,0},{5,0},{5,1} }
};
t2DArray *GetArray;
int main()
{
GetArray = &TwoDArray;
printf("/n %d/n %d/n %d/n %d/n %d/n %d/n",
GetArray->Array[0][0],
GetArray->Array[0][1],
GetArray->Array[1][0],
GetArray->Array[1][1],
GetArray->Array[2][0],
GetArray->Array[2][1]);
getchar();
return 0;
}
FUERA
12 5 4 8 3 6
Una matriz 2D se ve como una matriz de matrices 1D. Es decir, cada fila en una matriz 2D es una matriz 1D. Por lo tanto, dado una matriz 2D A
,
int A[m][n].
En general,
A[i][j] = *(A[i]+j)
además
A[i] = *(A+i)
asi que,
A[i][j] = *(A[i]+j) = * ( *(A+i)+j).
Resumen: si tiene una matriz multidimensional definida como int [][]
, entonces x = y[a][b]
es equivalente a x = *((int *)y + a * NUMBER_OF_COLUMNS + b);
Detalles aburridos:
El (int *)
elenco de y
anterior merece alguna explicación, ya que su necesidad puede no ser al principio intuitiva. Para entender por qué debe estar allí, considere lo siguiente:
La aritmética del puntero tipeado en C / C ++ siempre ajusta el valor del puntero tipeado (que es una dirección) por el tamaño del tipo en bytes al agregar / restar / incrementar / decrementar por escalar.
El tipo fundamental de una declaración de matriz multidimensional (no el tipo de elemento, el tipo de variable ) es un tipo de matriz de dimensión única que la dimensión final.
El último (n. ° 2) de estos realmente necesita un ejemplo para solidificarse. En lo que sigue, las variables ar1
y ar2
son declaraciones equivalentes.
int ar1[5][5]; // an array of 5 rows of 5 ints.
typedef int Int5Array[5]; // type is an array of 5 ints
Int5Array ar2[5]; // an array of 5 Int5Arrays.
Ahora la parte aritmética del puntero. Del mismo modo que un puntero de estructura tipada puede avanzarse por el tamaño de la estructura en bytes, también se puede saltear una dimensión completa de una matriz. Esto es más fácil de entender si piensas en la matriz multidimensional como he declarado ar2 arriba:
int (*arptr)[5] = ar1; // first row, address of ar1[0][0].
++arptr; // second row, address of ar[1][0].
Todo esto desaparece con un simple puntero:
int *ptr = ar1; // first row, address of ar1[0][0].
++ptr; // first row, address of ar1[0][1].
Por lo tanto, al hacer la aritmética del puntero para una matriz bidimensional, NO funcionaría lo siguiente al obtener el elemento en [2][2]
de una matriz multidimensional:
#define NUMBER_OF_COLUMNS 5
int y[5][NUMBER_OF_COLUMNS];
int x = *(y + 2 * NUMBER_OF_COLUMNS + 2); // WRONG
La razón es, con suerte, obvia cuando recuerdas que y
es una matriz de matrices (declarativamente hablando). La aritmética del puntero para agregar el escalador (2*5 + 2)
a y
agregará 12 filas , por lo que la computación y la dirección equivalen a &(y[12])
, lo que claramente no es correcto, y de hecho, arrojará una grasa advertencia en tiempo de compilación o directamente no compilar por completo. Esto se evita con el molde de (int*)y
y el tipo resultante de la expresión se basa en un puntero desnudo a int:
#define NUMBER_OF_COLUMNS 5
int y[5][NUMBER_OF_COLUMNS];
int x = *((int *)y + 2 * NUMBER_OF_COLUMNS + 2); // Right!
#include <iostream>
using namespace std;
int main()
{
//FOR 1-D ARRAY THROUGH ARRAY
int brr[5]= {1,2,3,4,5};
for(int i=0; i<5; i++)
{
cout<<"address ["<<i<<"] = " <<&brr[i]<<" and value = "<<brr[i]<<endl;
}
//FOR 1-D ARRAY THROUGH POINTER
cout<<endl; // endl TO MAKE OUT PUT LOOK CLEAR AND COOL :)
int (*q)=brr;
for(int i=0; i<5; i++)
{
cout<<"address ["<<i<<"] = " <<&brr[i]<<" and value = "<<*(q+i)<<endl; //(p[i][j])
}
cout<<endl;
//FOR 2-D ARRAY THROUGH ARRAY
int arr[2][3] = {1,2,3,4,5,6};
for(int i=0; i<2; i++)
{
for(int j=0; j<3; j++)
{
cout<<"address ["<<i<<"]["<<j<<"] = " <<&arr[i][j]<<" and value = "<<arr[i][j]<<endl;
}
}
//FOR 2-D ARRAY THROUGH POINTER
int (*p)[3]=arr; // j value we give
cout<<endl;
for(int i=0; i<2; i++)
{
for(int j=0; j<3; j++)
{
cout<<"address ["<<i<<"]["<<j<<"] = " <<(*(p+i)+j)<<" and value = "<<(*(*(p+i)+j))<<endl; //(p[i][j])
}
}
return 0;
}
==============OUT PUT======================
//FOR 1-D ARRAY THROUGH ARRAY
address [0] = 0x28fed4 and value = 1
address [1] = 0x28fed8 and value = 2
address [2] = 0x28fedc and value = 3
address [3] = 0x28fee0 and value = 4
address [4] = 0x28fee4 and value = 5
//FOR 1-D ARRAY THROUGH POINTER
address [0] = 0x28fed4 and value = 1
address [1] = 0x28fed8 and value = 2
address [2] = 0x28fedc and value = 3
address [3] = 0x28fee0 and value = 4
address [4] = 0x28fee4 and value = 5
//FOR 2-D ARRAY THROUGH ARRAY
address [0][0] = 0x28fee8 and value = 1
address [0][1] = 0x28feec and value = 2
address [0][2] = 0x28fef0 and value = 3
address [1][0] = 0x28fef4 and value = 4
address [1][1] = 0x28fef8 and value = 5
address [1][2] = 0x28fefc and value = 6
//FOR 2-D ARRAY THROUGH POINTER
address [0][0] = 0x28fee8 and value = 1
address [0][1] = 0x28feec and value = 2
address [0][2] = 0x28fef0 and value = 3
address [1][0] = 0x28fef4 and value = 4
address [1][1] = 0x28fef8 and value = 5
address [1][2] = 0x28fefc and value = 6