Crear un puntero a una matriz bidimensional

13 minutos de lectura

avatar de usuario
Eneldo

Necesito un puntero a una matriz bidimensional estática. ¿Cómo se hace esto?

static uint8_t l_matrix[10][20];

void test(){
   uint8_t **matrix_ptr = l_matrix; //wrong idea 
}

Recibo todo tipo de errores como:

  • advertencia: asignación de tipo de puntero incompatible
  • el valor con subíndice no es una matriz ni un puntero
  • error: uso no válido de miembro de matriz flexible

  • @ JohannesSchaub-litb Eso ya no existe. (¿Cómo lo veo de nuevo…? Yo saber los miembros de baja reputación pueden verlo, pero olvidé cómo…)

    –Mateen Ulhaq

    21 de octubre de 2011 a las 4:49


  • @muntoo: Aquí hay una copia: gist.github.com/sharth/ede13c0502d5dd8d45bd

    – Bill Lynch

    6 sep 2013 a las 16:13

avatar de usuario
Johannes Schaub – litb

Aquí quieres hacer un puntero al primer elemento de la matriz

uint8_t (*matrix_ptr)[20] = l_matrix;

Con typedef, esto se ve más limpio

typedef uint8_t array_of_20_uint8_t[20];
array_of_20_uint8_t *matrix_ptr = l_matrix;

Entonces podrás disfrutar de la vida de nuevo 🙂

matrix_ptr[0][1] = ...;

Tenga cuidado con el mundo del puntero/matriz en C, hay mucha confusión en torno a esto.


Editar

Revisando algunas de las otras respuestas aquí, porque los campos de comentarios son demasiado cortos para hacerlo allí. Se propusieron múltiples alternativas, pero no se mostró cómo se comportan. Así es como lo hacen

uint8_t (*matrix_ptr)[][20] = l_matrix;

Si corrige el error y agrega la dirección del operador & como en el siguiente fragmento

uint8_t (*matrix_ptr)[][20] = &l_matrix;

Luego, ese crea un puntero a un tipo de matriz incompleta de elementos de tipo matriz de 20 uint8_t. Debido a que el puntero es a una matriz de matrices, debe acceder a él con

(*matrix_ptr)[0][1] = ...;

Y debido a que es un puntero a una matriz incompleta, no poder hacer como un atajo

matrix_ptr[0][0][1] = ...;

Porque la indexación requiere que se conozca el tamaño del tipo de elemento (la indexación implica la adición de un número entero al puntero, por lo que no funcionará con tipos incompletos). Tenga en cuenta que esto sólo funciona en Cporque T[] y T[N] son tipos compatibles. C++ no tiene un concepto de tipos compatiblespor lo que rechazará ese código, porque T[] y T[10] son de diferentes tipos.


La siguiente alternativa no funciona en absoluto, porque el tipo de elemento de la matriz, cuando la ve como una matriz unidimensional, es no uint8_tpero uint8_t[20]

uint8_t *matrix_ptr = l_matrix; // fail

La siguiente es una buena alternativa.

uint8_t (*matrix_ptr)[10][20] = &l_matrix;

Accedes con

(*matrix_ptr)[0][1] = ...;
matrix_ptr[0][0][1] = ...; // also possible now

Tiene la ventaja de que conserva el tamaño de la dimensión exterior. Entonces puedes aplicarle sizeof

sizeof (*matrix_ptr) == sizeof(uint8_t) * 10 * 20

Hay otra respuesta que hace uso del hecho de que los elementos de una matriz se almacenan de forma contigua

uint8_t *matrix_ptr = l_matrix[0];

Ahora, eso formalmente solo le permite acceder a los elementos del primer elemento de la matriz bidimensional. Es decir, se cumple la siguiente condición

matrix_ptr[0] = ...; // valid
matrix_ptr[19] = ...; // valid

matrix_ptr[20] = ...; // undefined behavior
matrix_ptr[10*20-1] = ...; // undefined behavior

Notarás que probablemente funciona hasta 10*20-1, pero si lanza un análisis de alias y otras optimizaciones agresivas, algún compilador podría suponer que puede romper ese código. Habiendo dicho eso, nunca me he encontrado con un compilador que falle (pero, de nuevo, no he usado esa técnica en código real), e incluso las preguntas frecuentes de C contienen esa técnica (con una advertencia sobre su UB). ), y si no puede cambiar el tipo de matriz, esta es la última opción para salvarlo 🙂

  • +1 – buena información sobre el int[][20]

    desglose: no se puede hacer eso en C++

    – Faisal Vali

  • 27 de junio de 2009 a las 15:46

    @litb, lo siento, pero esto es incorrecto ya que su solución no proporciona ninguna asignación de almacenamiento para la matriz.

    – Rob Wells

  • 27 de junio de 2009 a las 18:11

    @Rob, no te entiendo muy bien. el almacenamiento en todos estos casos lo proporciona el propio arreglo l_matix. Los punteros a ellos se almacenan desde donde se declaran y como (pila, segmento de datos estáticos, …).

    – Johannes Schaub – litb

  • 27 de junio de 2009 a las 19:32

    Solo por curiosidad, ¿por qué necesitamos la dirección “&” de l_matrix?

    – electro

  • 28 de marzo de 2017 a las 23:41 uint8_t *d[20]@Sohaib: no, eso crea solo un puntero. Puede que lo hayas confundido con

    que crea una matriz de 3 punteros a uint8_t, pero eso no funcionaría en este caso.

    – Palo

7 de julio de 2018 a las 0:59
avatar de usuario

Super gato Para completamente entiende esto, tu deber

captar los siguientes conceptos:

¡Las matrices no son punteros! En primer lugar (y se ha predicado lo suficiente),las matrices no son punteros

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

int *p = a; // p now points to a[0]

. En cambio, en la mayoría de los usos, “decaen” a la dirección de su primer elemento, que se puede asignar a un puntero:



Supongo que funciona de esta manera para que se pueda acceder al contenido de la matriz sin copiarlos todos. Eso es solo un comportamiento de los tipos de matriz y no implica que sean lo mismo.

Matrices multidimensionales

Las matrices multidimensionales son solo una forma de ‘particionar’ la memoria de una manera que el compilador / máquina pueda entender y operar. int a[4][3][5] Por ejemplo,

= una matriz que contiene 4*3*5 (60) ‘trozos’ de memoria de tamaño entero. int a[4][3][5] La ventaja sobre el uso int b[60] vs simple

es que ahora están ‘particionados’ (es más fácil trabajar con sus ‘fragmentos’, si es necesario), y el programa ahora puede realizar una verificación de límites. int a[4][3][5] De hecho, está almacenado exactamente int b[60] me gusta en la memoria – El solamente

la diferencia es que el programa ahora lo maneja como si fueran entidades separadas de ciertos tamaños (Específicamente, cuatro grupos de tres grupos de cinco). int a[4][3][5] Tenga en cuenta: Ambos int b[60] y

{
  {1, 2, 3, 4, 5}
  {6, 7, 8, 9, 10}
  {11, 12, 13, 14, 15}
}
{
  {16, 17, 18, 19, 20}
  {21, 22, 23, 24, 25}
  {26, 27, 28, 29, 30}
}
{
  {31, 32, 33, 34, 35}
  {36, 37, 38, 39, 40}
  {41, 42, 43, 44, 45}
}
{
  {46, 47, 48, 49, 50}
  {51, 52, 53, 54, 55}
  {56, 57, 58, 59, 60}
}

son iguales en la memoria, y la única diferencia es cómo los maneja la aplicación/compilador



A partir de esto, puede ver claramente que cada “partición” es solo una matriz de la que el programa realiza un seguimiento.

Sintaxis Ahora,las matrices son sintácticamente diferentes de los punteros . Específicamente, esto significa el compilador/máquina los tratará de manera diferente.

int a[3][3];

printf("%p %p", a, a[0]);

Esto puede parecer una obviedad, pero echa un vistazo a esto:

0x7eb5a3b4 0x7eb5a3b4

El ejemplo anterior imprime la misma dirección de memoria dos veces, así:Sin embargo, solo se puede asignar uno a un puntero de forma tan directa

int *p1 = a[0]; // RIGHT !

int *p2 = a; // WRONG !

: a ¿Por qué no puedo? a[0] ser asignado a un puntero pero

¿puede?

Esto, simplemente, es una consecuencia de los arreglos multidimensionales, y explicaré por qué:aAl nivel de ‘a[0]‘, todavía vemos que tenemos otra ‘dimensión’ que esperar. Al nivel de ‘

‘, sin embargo, ya estamos en la dimensión superior, por lo que en lo que respecta al programa, solo estamos viendo una matriz normal.

Usted puede estar preguntando:

¿Por qué importa si la matriz es multidimensional en lo que respecta a hacer un puntero para ella?

Lo mejor es pensar de esta manera: Una ‘desintegración’ de una matriz multidimensional no es solo una dirección, sino una dirección con datos de partición

(AKA, todavía entiende que sus datos subyacentes están hechos de otras matrices), que consisten en límites establecidos por la matriz más allá de la primera dimensión.

int a[4][5][95][8];

int (*p)[5][95][8];

p = a; // p = *a[0] // p = a+0

Esta lógica de ‘partición’ no puede existir dentro de un puntero a menos que lo especifiquemos:

De lo contrario, se pierde el significado de las propiedades de clasificación de la matriz. *pTambién tenga en cuenta el uso de paréntesis alrededor int (*p)[5][95][8] : int *p[5][95][8]



– Eso es para especificar que estamos creando un puntero con estos límites, no una matriz de punteros con estos límites:

Conclusión

  • Revisemos:
  • Las matrices se descomponen en direcciones si no tienen otro propósito en el contexto utilizado
  • Los arreglos multidimensionales son solo arreglos de arreglos; por lo tanto, la dirección ‘descompuesta’ llevará la carga de “Tengo subdimensiones” Los datos de dimensión no pueden existir en un punteroa menos que se lo des

.

  • En resumen: las matrices multidimensionales se degradan en direcciones que tienen la capacidad de comprender su contenido. int *p1 = &(a[0]); // RIGHT !La primera parte de la respuesta es excelente, pero la segunda no lo es. Esto no es correcto: int *p1 = a;

    en realidad es idéntico a

    – 2501


  • 25 de abril de 2016 a las 9:12

    @ 2501 Gracias por detectar ese error, lo he corregido. No puedo decir con certeza por qué el ejemplo que define esta “regla” también la desafió. Vale la pena reiterar que el hecho de que dos entidades se puedan interpretar como punteros y produzcan el mismo valor no significa que tengan el mismo significado.

    – Super gato


  • 29 de abril de 2016 a las 2:42

    Solo el compilador ve matrices y punteros de manera diferente. Durante el tiempo de ejecución, las matrices degeneran en nada más que punteros constantes.

    – John Strod

9 sep 2021 a las 17:21
avatar de usuario

sagar

int *ptr= l_matrix[0];

En

*p
*(p+1)
*(p+2)

puedes acceder como

  • *(p+k) después de que todas las matrices bidimensionales también se almacenen como 1-d. p[k]es literalmente solo

    !

    – John Strod

9 sep 2021 a las 17:22
avatar de usuario

robar pozos

buen día,

static uint8_t l_matrix[10][20];

La declaracion

ha reservado almacenamiento para 10 filas de 20 ubicaciones unit8_t, es decir, 200 ubicaciones de tamaño uint8_t, y cada elemento se encuentra calculando 20 x fila + columna.

uint8_t (*matrix_ptr)[20] = l_matrix;

entonces no

darle lo que necesita y apuntar al elemento de la columna cero de la primera fila de la matriz? Editar:[0][0]Pensando un poco más en esto, ¿no es un nombre de matriz, por definición, un puntero? Es decir, el nombre de una matriz es sinónimo de la ubicación del primer elemento, es decir, l_matrix

? Edit2:

typedef uint8_t array_of_20_uint8_t[20];
array_of_20_uint8_t *matrix_ptr = l_matrix;

Como lo mencionaron otros, el espacio para comentarios es un poco pequeño para una mayor discusión. De todas formas:

no proporciona ninguna asignación de almacenamiento para el arreglo en cuestión.

static uint8_t l_matrix[10][20];

Como se mencionó anteriormente, y según lo define el estándar, la declaración:

ha reservado 200 ubicaciones secuenciales de tipo uint8_t.

(*l_matrix + (20 * rowno) + colno)

Refiriéndose a l_matrix usando declaraciones de la forma:

le dará el contenido del elemento colno’th que se encuentra en la fila rowno.

Todas las manipulaciones del puntero tienen en cuenta automáticamente el tamaño del objeto al que se apunta. – K&R Sección 5.4, p.103 Este también es el caso si cualquier cambio de alineación de byte o relleno está involucrado en el almacenamiento del objeto en cuestión. El compilador se ajustará automáticamente a estos.

Por definición del estándar C ANSI.

HTH

salud,
avatar de usuario

Kornel

int l_matrix[10][20];

void test(int matrix_ptr[static 10][20]) {
}

int main(void) {
    test(l_matrix);
}

En C99 (compatible con clang y gcc) hay una sintaxis oscura para pasar matrices multidimensionales a funciones por referencia: A diferencia de un puntero simple, esto sugiere el tamaño de la matriz, teóricamente

permitiendo que el compilador advierta sobre el paso de una matriz demasiado pequeña y detecte un acceso obvio fuera de los límites. sizeof() lamentablemente no se soluciona

  • y los compiladores no parecen usar esa información todavía, por lo que sigue siendo una curiosidad. static 10 Esta respuesta es engañosa: eso no hace que el argumento sea una matriz de tamaño fijo, sigue siendo un puntero. es una especie de garantía de que al menos

    10 elementos están presentes, lo que nuevamente significa que el tamaño no es fijo.

    – sonrojarse

  • 26 de noviembre de 2016 a las 13:04 @bluss la pregunta era sobre un puntero, por lo que no veo cómo responder con un puntero (observandopor referencia

    ) es engañosa. La matriz tiene un tamaño fijo desde la perspectiva de la función, porque el acceso a elementos más allá de estos límites no está definido.

    – Kornel

  • 26 de noviembre de 2016 a las 19:03

    No creo que el acceso más allá de 10 no esté definido, no puedo ver nada que lo indique.

    – sonrojarse

  • 26 de noviembre de 2016 a las 23:11 staticEsta respuesta parece sugerir que sin la palabra clave

    , la matriz no se pasaría por referencia, lo cual no es cierto. Las matrices se pasan por referencia de todos modos. La pregunta original se refería a un caso de uso diferente: acceder a elementos de una matriz 2D utilizando un puntero adicional dentro de la misma función/espacio de nombres.

    – Palo

7 de julio de 2018 a las 0:43
avatar de usuario

gnosis

static uint8_t l_matrix[200];

void test(int row, int col, uint8_t val)

{

   uint8_t* matrix_ptr = l_matrix;
   matrix_ptr [col+y*row] = val; // to assign a value

}

Siempre puede evitar jugar con el compilador declarando la matriz como lineal y haciendo el cálculo del índice (fila, columna) para la matriz usted mismo.

  • esto es lo que el compilador habría hecho de todos modos. static 10 Esta respuesta es engañosa: eso no hace que el argumento sea una matriz de tamaño fijo, sigue siendo un puntero. es una especie de garantía de que al menos

    10 elementos están presentes, lo que nuevamente significa que el tamaño no es fijo.

    – sonrojarse

  • 26 de noviembre de 2016 a las 13:04 @bluss la pregunta era sobre un puntero, por lo que no veo cómo responder con un puntero (observandopor referencia

    ) es engañosa. La matriz tiene un tamaño fijo desde la perspectiva de la función, porque el acceso a elementos más allá de estos límites no está definido.

    – Kornel

  • 26 de noviembre de 2016 a las 19:03

    No creo que el acceso más allá de 10 no esté definido, no puedo ver nada que lo indique.

    – sonrojarse

  • 26 de noviembre de 2016 a las 23:11 staticEsta respuesta parece sugerir que sin la palabra clave

    , la matriz no se pasaría por referencia, lo cual no es cierto. Las matrices se pasan por referencia de todos modos. La pregunta original se refería a un caso de uso diferente: acceder a elementos de una matriz 2D utilizando un puntero adicional dentro de la misma función/espacio de nombres.

    – Palo

7 de julio de 2018 a las 0:43
avatar de usuario

MAChitgarha

type (*pointer)[1st dimension size][2nd dimension size][..] = &array_name

La sintaxis básica del puntero de inicialización que apunta a una matriz multidimensional es

(*pointer_name)[1st index][2nd index][...]

La sintaxis básica para llamarlo es

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
   // The multidimentional array...
   char balance[5][100] = {
       "Subham",
       "Messi"
   };

   char (*p)[5][100] = &balance; // Pointer initialization...

   printf("%s\n",(*p)[0]); // Calling...
   printf("%s\n",(*p)[1]); // Calling...

  return 0;
}

Aquí hay un ejemplo:

Subham
Messi

La salida es:

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad