Puntero C a matriz/matriz de desambiguación de punteros

5 minutos de lectura

avatar de usuario
Jorge

¿Cuál es la diferencia entre las siguientes declaraciones:

int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);

¿Cuál es la regla general para comprender declaraciones más complejas?

  • Aquí hay un gran artículo sobre la lectura de declaraciones complejas en C: unixwiz.net/techtips/reading-cdecl.html

    – bufón

    27/01/2013 a las 13:00

  • @jesper Desafortunadamente, el const y volatile los calificadores, que son importantes y complicados, faltan en ese artículo.

    – no-un-usuario

    18 mayo 2017 a las 15:32

avatar de usuario
jugo de sig

Utilizar el cdecl programa, como lo sugiere K&R.

$ cdecl
Type `help' or `?' for help
cdecl> explain int* arr1[8];
declare arr1 as array 8 of pointer to int
cdecl> explain int (*arr2)[8]
declare arr2 as pointer to array 8 of int
cdecl> explain int *(arr3[8])
declare arr3 as array 8 of pointer to int
cdecl>

También trabaja de la otra manera.

cdecl> declare x as pointer to function(void) returning pointer to float
float *(*x)(void )

  • @ankii La mayoría de las distribuciones de Linux deberían tener un paquete. También puede construir su propio binario.

    – jugo de sig

    15 oct 2019 a las 17:05

  • ah, lo siento por no mencionar, macOS aquí. Veré si está disponible, de lo contrario, el sitio web también está bien. ^^ gracias por informarme sobre esto. Siéntase libre de marcar NLN.

    usuario10063119

    15 oct 2019 a las 17:06


  • @ankii Puede instalar desde Homebrew (¿y tal vez MacPorts?). Si no son de su agrado, es trivial crear uno propio desde el enlace de Github en la parte superior derecha de cdecl.org (lo acabo de crear en macOS Mojave). Luego simplemente copie el binario cdecl en su RUTA. Recomiendo $PATH/bin, porque no hay necesidad de involucrar a root en algo tan simple como esto.

    – jugo de sig

    15 oct 2019 a las 17:18

  • Oh, no había leído el pequeño párrafo sobre la instalación en Léame. solo algunos comandos y banderas para manejar dependencias. Instalado usando brew. 🙂

    usuario10063119

    15 oct 2019 a las 17:35

  • He oído referirse a ella con el nombre de “La regla de la espiral”, que se puede encontrar aquí.

    – fouric

    27 de mayo de 2013 a las 3:04

  • @InkBlend: la regla espiral es diferente de regla derecha-izquierda. El primero falla en casos como int *a[][10] mientras que este último lo consigue.

    – leyendas2k

    9 oct 2013 a las 13:51


  • Como dijeron InkBlend y legends2k, esta es la regla espiral, que es más compleja y no funciona en todos los casos, por lo que no hay razón para usarla.

    – kotlomoy

    25/09/2014 a las 18:29

  • No olvide la asociatividad de izquierda a derecha de ( ) [ ] y de derecha a izquierda de * &

    – blanda

    23 de septiembre de 2017 a las 14:10

  • @legends2k: ¿Cuál es la lectura de declaración para int *a?[][10]

    – Chico bestia

    21 de noviembre de 2018 a las 4:37

La respuesta para los dos últimos también se puede deducir de la regla de oro en C:

La declaración sigue al uso.

int (*arr2)[8];

¿Qué pasa si desreferencias? arr2? Obtienes una matriz de 8 enteros.

int *(arr3[8]);

¿Qué pasa si tomas un elemento de arr3? Obtienes un puntero a un número entero.

Esto también ayuda cuando se trata de punteros a funciones. Para tomar el ejemplo de sigjuice:

float *(*x)(void )

¿Qué sucede cuando desreferencias? x? Obtienes una función a la que puedes llamar sin argumentos. ¿Qué pasa cuando lo llamas? Devolverá un puntero a un float.

Sin embargo, la precedencia de los operadores siempre es complicada. Sin embargo, el uso de paréntesis también puede resultar confuso porque la declaración sigue al uso. Al menos, para mí, intuitivamente arr2 parece una matriz de 8 punteros a enteros, pero en realidad es al revés. Solo toma algo de tiempo acostumbrarse. Razón suficiente para agregar siempre un comentario a estas declaraciones, si me preguntas 🙂

editar: ejemplo

Por cierto, me topé con la siguiente situación: una función que tiene una matriz estática y que usa aritmética de punteros para ver si el puntero de fila está fuera de los límites. Ejemplo:

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

#define NUM_ELEM(ar) (sizeof(ar) / sizeof((ar)[0]))

int *
put_off(const int newrow[2])
{
    static int mymatrix[3][2];
    static int (*rowp)[2] = mymatrix;
    int (* const border)[] = mymatrix + NUM_ELEM(mymatrix);

    memcpy(rowp, newrow, sizeof(*rowp));
    rowp += 1;
    if (rowp == border) {
        rowp = mymatrix;
    }

    return *rowp;
}

int
main(int argc, char *argv[])
{
    int i = 0;
    int row[2] = {0, 1};
    int *rout;

    for (i = 0; i &lt; 6; i++) {
        row[0] = i;
        row[1] += i;
        rout = put_off(row);
        printf("%d (%p): [%d, %d]\n", i, (void *) rout, rout[0], rout[1]);
    }

    return 0;
}

Producción:

0 (0x804a02c): [0, 0]
1 (0x804a034): [0, 0]
2 (0x804a024): [0, 1]
3 (0x804a02c): [1, 2]
4 (0x804a034): [2, 4]
5 (0x804a024): [3, 7]

Tenga en cuenta que el valor del borde nunca cambia, por lo que el compilador puede optimizarlo. Esto es diferente de lo que podría querer usar inicialmente: const int (*border)[3]: que declara el borde como un puntero a una matriz de 3 enteros que no cambiarán de valor mientras exista la variable. Sin embargo, ese puntero puede apuntar a cualquier otra matriz en cualquier momento. En cambio, queremos ese tipo de comportamiento para el argumento (porque esta función no cambia ninguno de esos enteros). La declaración sigue al uso.

(PD: ¡siéntete libre de mejorar esta muestra!)

avatar de usuario
gary

int *a[4]; // Array of 4 pointers to int

int (*a)[4]; //a is a pointer to an integer array of size 4

int (*a[8])[5]; //a is an array of pointers to integer array of size 5 

avatar de usuario
Abhishek Jaisingh

Aquí hay un sitio web interesante que explica cómo leer tipos complejos en C:
http://www.unixwiz.net/techtips/reading-cdecl.html

¿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