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 subindicado no es ni una matriz ni un puntero
- error: uso no válido del miembro de matriz flexible
Respuestas:
Aquí quieres hacer un puntero al primer elemento de la matriz.
Con typedef, esto se ve más limpio
Entonces podrás volver a disfrutar de la vida :)
Tenga cuidado con el mundo de punteros / matrices en C, hay mucha confusión alrededor de 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
Si corrige el error y agrega el operador de dirección de
&
como en el siguiente fragmentoLuego, 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
Y debido a que es un puntero a una matriz incompleta, no puede hacerlo como un atajo
Debido a que la indexación requiere que se conozca el tamaño del tipo de elemento (la indexación implica una adición de un número entero al puntero, por lo que no funcionará con tipos incompletos). Tenga en cuenta que esto solo funciona en
C
, porqueT[]
yT[N]
son tipos compatibles. C ++ no tiene un concepto de tipos compatibles , por lo que rechazará ese código, porqueT[]
yT[10]
son tipos diferentes.La siguiente alternativa no funciona en absoluto, porque el tipo de elemento de la matriz, cuando lo ve como una matriz unidimensional, no lo es
uint8_t
, perouint8_t[20]
La siguiente es una buena alternativa
Lo accedes con
Tiene la ventaja de que conserva el tamaño de la dimensión exterior. Entonces puedes aplicar sizeof en él
Hay otra respuesta que hace uso del hecho de que los elementos de una matriz se almacenan contiguamente
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
Notará que probablemente funciona
10*20-1
, pero si agrega análisis de alias y otras optimizaciones agresivas, algún compilador podría hacer una suposición que podría romper ese código. Habiendo dicho eso, nunca me he encontrado con un compilador que falle en él (pero, de nuevo, no he usado esa técnica en código real), e incluso el C FAQ contiene esa técnica (con una advertencia sobre su UB'ness ), y si no puede cambiar el tipo de matriz, esta es la última opción para salvarlo :)fuente
uint8_t *d[20]
, que crea una matriz de 3 punteros a uint8_t, pero eso no funcionaría en este caso.Para comprender completamente esto, debe comprender los siguientes conceptos:
¡Las matrices no son punteros!
En primer lugar (y se ha predicado lo suficiente), las matrices no son punteros . En cambio, en la mayoría de los usos, 'decaen' a la dirección de su primer elemento, que puede asignarse 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 tipos de matriz y no significa que sean lo mismo.
Matrices multidimensionales
Los arreglos multidimensionales son solo una forma de 'particionar' la memoria de una manera que el compilador / máquina pueda entender y operar.
Por ejemplo,
int a[4][3][5]
= una matriz que contiene 4 * 3 * 5 (60) 'trozos' de memoria de tamaño entero.La ventaja sobre el uso
int a[4][3][5]
frente al simpleint b[60]
es que ahora están "particionados" (es más fácil trabajar con sus "fragmentos", si es necesario), y el programa ahora puede realizar comprobaciones vinculadas.De hecho,
int a[4][3][5]
se almacena exactamente comoint b[60]
en la memoria: la única diferencia es que el programa ahora lo administra como si fueran entidades separadas de ciertos tamaños (específicamente, cuatro grupos de tres grupos de cinco).Tenga en cuenta: Ambos
int a[4][3][5]
yint b[60]
son iguales en memoria, y la única diferencia es cómo los maneja la aplicación / compiladorA 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 que el compilador / máquina los tratará de manera diferente. Esto puede parecer una obviedad, pero eche un vistazo a esto:
El ejemplo anterior imprime la misma dirección de memoria dos veces, así:
Sin embargo, solo se puede asignar uno a un puntero de manera tan directa :
¿Por qué no se
a
puede asignar a un puntero peroa[0]
sí?Esto, simplemente, es una consecuencia de las matrices multidimensionales, y explicaré por qué:
En el nivel de "
a
", todavía vemos que tenemos otra "dimensión" que esperar.a[0]
Sin embargo, en el nivel de " ", ya estamos en la dimensión superior, por lo que en lo que respecta al programa, solo estamos viendo una matriz normal.Puede estar preguntando:
¿Por qué importa si la matriz es multidimensional en lo que respecta a hacer un puntero para ella?
Es mejor pensar de esta manera:
Un 'decaimiento' de una matriz multidimensional no es solo una dirección, sino una dirección con datos de partición (también conocido como aún entiende que sus datos subyacentes están hechos de otras matrices), que consiste en límites establecidos por la matriz más allá de la primera dimensión.
Esta lógica de 'partición' no puede existir dentro de un puntero a menos que la especifiquemos:
De lo contrario, se pierde el significado de las propiedades de clasificación de la matriz.
También tenga en cuenta el uso de paréntesis alrededor de
*p
:int (*p)[5][95][8]
- Eso es para especificar que estamos haciendo un puntero con estos límites, no una matriz de punteros con estos límites:int *p[5][95][8]
Conclusión
Revisemos:
En resumen: los arreglos multidimensionales decaen hacia direcciones que tienen la capacidad de comprender su contenido.
fuente
int *p1 = &(a[0]); // RIGHT !
realidad es idéntico aint *p1 = a;
En
puedes acceder como
después de que todas las matrices bidimensionales también se almacenan como 1-d.
fuente
Buenos dias
La declaracion
ha reservado almacenamiento para 10 filas de 20 ubicaciones unit8_t, es decir, 200 ubicaciones del tamaño de uint8_t, y cada elemento se encuentra calculando 20 x fila + columna.
Entonces no
darle lo que necesita y señalar el elemento de la columna cero de la primera fila de la matriz?
Editar: Pensando en esto un poco más, ¿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 [0] [0]?
Edit2: Como lo mencionaron otros, el espacio de comentarios es demasiado pequeño para una discusión adicional. De todas formas:
no proporciona ninguna asignación de almacenamiento para la matriz en cuestión.
Como se mencionó anteriormente, y según lo definido por el estándar, la declaración:
ha reservado 200 ubicaciones secuenciales de tipo uint8_t.
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.
Este también es el caso si hay algún cambio de alineación de byte o relleno 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,
fuente
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, lo que teóricamente permite que el compilador advierta sobre el paso de una matriz demasiado pequeña y detecte un acceso obvio fuera de los límites.
Lamentablemente, no se corrige
sizeof()
y los compiladores no parecen usar esa información todavía, por lo que sigue siendo una curiosidad.fuente
static 10
es una especie de garantía de que están presentes al menos 10 elementos, lo que nuevamente significa que el tamaño no es fijo.static
, 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 suplementario dentro de la misma función / espacio de nombres.Siempre puede evitar jugar con el compilador declarando la matriz como lineal y haciendo el (fila, columna) al cálculo del índice de matriz usted mismo.
esto es lo que habría hecho el compilador de todos modos.
fuente
La sintaxis básica de la inicialización del puntero que apunta a una matriz multidimensional es
type (*pointer)[1st dimension size][2nd dimension size][..] = &array_name
La sintaxis básica para llamarlo es
He aquí un ejemplo:
La salida es:
Funcionó...
fuente
Puedes hacerlo así:
fuente
Quieres un puntero al primer elemento, entonces;
fuente
También puede agregar un desplazamiento si desea utilizar índices negativos:
Si su compilador da un error o advertencia, puede usar:
fuente
c
, por lo que la respuesta debe estar en el mismo idioma. Observe las etiquetas.