En el siguiente fragmento de código, obtengo los dos primeros valores de direcciones iguales (llámelo x). Lo he ejecutado en el compilador gcc de ubuntu v18.04.4 LTS.

  int a[2][2] = {0};
  printf("%p %p %d\n", a, *a, **a);

Esto significa que:

  1. a contiene la dirección x.
  2. a apunta a la ubicación x (ya que es un puntero que almacena x).
  3. esto significa que * a se almacena en la ubicación x y también contiene el valor x (como en la salida del código anterior).
  4. ahora, al cancelar la referencia * a, es decir, ** a, obtengo la salida como 0, lo que significa que * a (cuyo valor es x) apunta a alguna ubicación en la que se almacena 0.

Ahora, desde 1., la dirección de * a es x (como apunta a * a y está almacenando x) y la dirección del número 0 también es x (como * a apunta a un [0] [0] que es 0 y * a está almacenando x). Entonces mi pregunta es ¿qué se almacena exactamente en la ubicación x? ¿O he confundido algo al sacar las conclusiones?

1
Saket Singh 25 jun. 2020 a las 14:55

2 respuestas

Su afirmación de que a contiene una dirección parece indicar que cree que a es un puntero. No es un puntero sino una matriz. Están relacionados, pero no son lo mismo.

Una matriz, en la mayoría de los contextos, decae a un puntero a su primer miembro. En este caso, esto significa que en una expresión a es lo mismo que &a[0] y *a es lo mismo que a[0] que es lo mismo que &a[0][0]. Esto también significa que la dirección de una matriz es la misma que la de su primer miembro, que es lo que está viendo cuando imprime a y *a.

Esto probablemente se ilustraría mejor con un diagrama:

      -----   -------   ----  ---
0x100 | 0 |   a[0][0]   a[0]  a
      -----   -------   
0x104 | 0 |   a[0][1]
      -----   -------   ----
0x108 | 0 |   a[1][0]   a[1]
      -----   -------
0x10c | 0 |   a[1][1]
      -----   -------   ----  ---

Desde aquí, puede ver que a comienza en la dirección 0x100 (x en su ejemplo) y contiene un total de 4 valores int. También tenga en cuenta que la submatriz a[0] tiene la misma dirección que a, al igual que el elemento inicial int a[0][0].

0
dbush 25 jun. 2020 a las 12:25

No he entendido qué es la magia 'x' .;)

Declaraste una matriz bidimensional

int a[2][2] = {0};

Los designadores de matriz utilizados en expresiones (con raras excepciones como, por ejemplo, usarlos en el operador sizeof) se convierten implícitamente en punteros a sus primeros elementos.

Entonces, la expresión a utilizada en esta llamada

printf("%p %p %d\n", a, *a, **a);

Se convierte en el puntero del tipo int ( * )[2] al primer elemento de la matriz. Es decir, es la dirección de la extensión de memoria ocupada por la matriz.

Usando el operador de indirección *, la expresión *a produce el primer elemento del tipo int[2] de la matriz original a.

Nuevamente, este designador de matriz *a en la llamada de printf se convierte implícitamente en un puntero del tipo int * a su primer elemento que tiene el tipo int. Este puntero contendrá la misma dirección de la extensión de memoria ocupada por la matriz original.

En esta expresión **a se aplican dos operadores de indirección. El primer operador de indirección produce el primer elemento de la matriz bidimensional, es decir, produce una matriz del tipo int[2]. Esta matriz utilizada como un operando del segundo operador de indirección a la vez se convierte implícitamente en puntero a su primer elemento que tiene el tipo int *. El segundo operador de indirección produce el objeto señalado por el puntero que es el objeto de la matriz original a[0][0].

Para que quede más claro, el primer operador de indirección *a es equivalente a usar el operador de subíndice a [0]. Y el segundo operador de indirección aplicado a esta expresión *a[0] es equivalente a la expresión a[0][0].

1
Vlad from Moscow 25 jun. 2020 a las 12:16