Estoy estudiando un poco de C++ y estoy luchando con los punteros. Entiendo que puede tener de 3 a nivel de los punteros, al declarar:

int *(*x)[5];

para que *x es un puntero a un array de 5 elementos que son punteros a int.
También sé que x[0] = *(x+0);, x[1] = *(x+1)y así sucesivamente….

Así, habida cuenta de la declaración anterior, ¿por qué es x[0] != x[0][0] != x[0][0][0] ?

  • …¿no es el mismo que int** x[5]? es decir, los paréntesis no cambia nada, ¿verdad?
  • x[0] , x[0][0] y x[0][0][0] tienen diferentes tipos. No se puede comparar. ¿Qué entiende usted por != ?
  • ellos no son el mismo: int **x[5] es un array de 5 elementos. Un elemento es un puntero a puntero a int
  • Me refiero a que theis direcciones son diferentes, incluso si x[0] ,x[0][0] ,x[0][0][0] es equivalente a *(x+0), *(x+0+0), *(x+0+0+0)
  • int** x[5] sería una matriz de cinco punteros que señalan a los punteros que apuntan a int. int *(*x)[5] es un puntero a una matriz de cinco punteros que apuntan a int.
  • escriba la dirección: &x[0] o : address of ...
  • Ahhh, a la derecha, está bien. Puntero de la sintaxis puede llegar a confundir. >_>
  • a la derecha-a la izquierda de la regla , spirale regla , C galimatías ↔ inglés y su’ en su camino a convertirse en un tres estrellas programador 🙂
  • Bien, yo no entiendo la sintaxis para tales arcanos estructuras como puntero-a-función (incluso uno de devolver un puntero-a-función… creo que… no lo han hecho recientemente, gracias a std::function, y tal vez nunca lo hará otra vez) o la referencia a la matriz, pero este uso, supongo que me pilló con la guardia baja.
  • Si tienes que luchar con los punteros de la definición es demasiado complicado. typedef int *ptr; typedef ptr arr[5]; arr *x;
  • x[0] != x[0][0] no es cierto: es absurdo.
  • Esta pregunta es poco práctico y es tonto con una simple respuesta a esta: cada puntero a otro puntero tiene su propia dirección. Simple.
  • En primer lugar, usted tiene dos niveles de punteros aquí, no tres. En segundo lugar, ¿qué x[0] != x[0][0] != x[0][0][0] decir? Esto no es una comparación válida en C++. Incluso si usted se divide en x[0] != x[0][0] y x[0][0] != x[0][0][0] aún no es válido. Así que, ¿qué hace su pregunta significa?
  • Causa la pregunta es estúpida. Si no hay nada, que la línea podría causar un error de compilación.
  • Sólo quiero mencionar int x[5] no es un vector, es una matriz. En C++ hay una gran diferencia entre ellos!
  • tienes toda la razón.
  • ocultando la complejidad detrás de una matriz typedef sin duda hace las cosas aún más difíciles de entender. Matriz de definiciones de tipos se comportan unintuitively
  • este es el de ingeniería, no de la intuición. Si usted está adivinando acerca de cómo funcionan los arreglos, entonces no debería ser el uso de ellos.
  • por ejemplo, void f(foo x) { ...do stuff with x...) parece que no va a modificar nada en el llamador código; pero si foo es una matriz typedef entonces esto es una sorpresa desagradable. También, sizeof x se portan mal aquí.
  • Los punteros y los arrays son confusas y typedef crea más confusión en este caso. Mejor evitar typedef aquí.
  • Ese es un argumento de que las matrices son peligrosos en general. Una matriz typedef todavía ayuda aquí, sin embargo.
  • Es sólo una pregunta extraña… Que alguna vez le dijo a usted (o a donde ¿alguna vez has leído) que x[0][0][0] es igual a *x(0+0+0)? Si una lengua tiene tan horribles semántica sería claramente inutilizable. Considere la posibilidad de x[2][3][1] vs x[1][3][2]. Deben esperar a ser el mismo en cualquier idioma?
  • No tengo la rep a votar, pero la secundó.

InformationsquelleAutor Leo91 | 2015-07-05

11 Comentarios

  1. 258

    x es un puntero a una matriz de 5 punteros a int.

    x[0] es una matriz de 5 punteros a int.

    x[0][0] es un puntero a una int.

    x[0][0][0] es un int.

                           x[0]
       Pointer to array  +------+                                 x[0][0][0]         
    x -----------------> |      |         Pointer to int           +-------+
                   0x500 | 0x100| x[0][0]---------------->   0x100 |  10   |
    x is a pointer to    |      |                                  +-------+
    an array of 5        +------+                        
    pointers to int      |      |         Pointer to int                             
                   0x504 | 0x222| x[0][1]---------------->   0x222                    
                         |      |                                             
                         +------+                                             
                         |      |         Pointer to int                              
                   0x508 | 0x001| x[0][2]---------------->   0x001                    
                         |      |                                             
                         +------+                                             
                         |      |         Pointer to int                              
                   0x50C | 0x123| x[0][3]---------------->   0x123                    
                         |      |                                             
                         +------+                                             
                         |      |         Pointer to int                              
                   0x510 | 0x000| x[0][4]---------------->   0x000                    
                         |      |                                             
                         +------+                                             

    Se puede ver que

    • x[0] es una matriz y se convierten puntero a su primer elemento cuando se utiliza en una expresión (con algunas excepciones). Por lo tanto x[0] va a dar la dirección de su primer elemento x[0][0] que es 0x500.
    • x[0][0] contiene la dirección de un int que es 0x100.
    • x[0][0][0] contiene un int valor de 10.

    Así, x[0] es igual a &x[0][0]y por lo tanto, &x[0][0] != x[0][0].

    Por lo tanto, x[0] != x[0][0] != x[0][0][0].

    • Este diagrama es un poco confuso para mí: 0x100 debe aparecer inmediatamente a la izquierda de la caja que contiene 10, de la misma manera que 0x500 aparece a la izquierda de la caja. En lugar de tener lejos a la izquierda y abajo.
    • Yo no creo que debería ser confuso, pero cambios como por su sugerencia para más claridad.
    • Mi placer 🙂 la razón por La que el diagrama es bueno es porque usted incluso no necesita la explicación que le dio que le sigue. Que el diagrama de sí mismo es auto-explicativo que ya responde a la pregunta. El texto que sigue es simplemente un bono.
    • También puede utilizar yed, un software de diagramación. Me ayuda mucho para organizar mis pensamientos
    • href=»http://asciiflow.com/#Draw» >AsciFlow también es bueno
    • Yo uso asciiflow por los comentarios del código, yeD para las presentaciones 🙂
    • Hola haccks!…..
    • Hola. ¿Cómo puedo ayudar?

  2. 133
    x[0] != x[0][0] != x[0][0][0]

    es, según su propio post,

    *(x+0) != *(*(x+0)+0) != *(*(*(x+0)+0)+0)`  

    que se simplifica

    *x != **x != ***x

    ¿Por qué debería ser igual?

    La primera es la dirección de un puntero.

    El segundo es el discurso del otro puntero.

    Y la tercera es que algunos int valor.

    • No entiendo… si x[0] ,x[0][0] ,x[0][0][0] es equivalente a *(x+0), *(x+0+0), *(x+0+0+0), ¿por qué deberían tener direcciones diferentes?
    • es (x[0])[0], es decir,*((*(x+0))+0), no *(x+0+0). Eliminar ocurre antes de la segunda [0].
    • como x[2][3] != x[3][2].
    • El segundo comentario que es «lo tengo ahora» fue quitado. Lo que no entiendes algo (lo que podría ser explicado mejor en la respuesta), o no es esto que estás haciendo? (algunas personas les gusta borrar comentarios sin mucho contenido informativo)
    • lo siento, no entiendo lo que quieres decir. Entiendo las respuestas así como también de muchos comentarios que ayudaron meto aclarar el concepto.
  3. 49

    Aquí es el diseño de memoria del puntero:

       +------------------+
    x: | address of array |
       +------------------+
                |
                V
                +-----------+-----------+-----------+-----------+-----------+
                | pointer 0 | pointer 1 | pointer 2 | pointer 3 | pointer 4 |
                +-----------+-----------+-----------+-----------+-----------+
                      |
                      V
                      +--------------+
                      | some integer |
                      +--------------+

    x[0] los rendimientos de la «dirección de la matriz»,

    x[0][0] rendimientos «puntero 0»,

    x[0][0][0] rendimientos «algunos entero».

    Creo, debería ser obvio ahora, ¿por qué todos ellos son diferentes.


    El de arriba es lo suficientemente cerca como para la comprensión básica, que es la razón por la que escribí es la forma en que lo escribí. Sin embargo, como haccks señala con razón, que la primera línea no es 100% precisa. Así que aquí vienen todos los detalles:

    A partir de la definición del lenguaje C, el valor de x[0] es toda la matriz de punteros de entero. Sin embargo, las matrices son algo que realmente no puedes hacer nada con en C. siempre manipular su dirección o la de sus elementos, nunca la totalidad de la matriz como un todo:

    1. Puede pasar x[0] a la sizeof operador. Pero eso no es realmente un uso del valor, su resultado depende de el tipo sólo.

    2. Usted puede tomar su dirección la cual se obtiene el valor de x, yo. e. «la dirección de la matriz» con el tipo de int*(*)[5]. En otras palabras: &x[0] <=> &*(x + 0) <=> (x + 0) <=> x

    3. En todos los demás contextos, el valor de x[0] se descompone, un puntero al primer elemento de la matriz. Es decir, un puntero con el valor de «dirección de la matriz» y el tipo int**. El efecto es el mismo como si se hubiera fundido x a un puntero de tipo int**.

    Debido a la serie del puntero de la caries en el caso 3., todos los usos de x[0] en última instancia resultar en un puntero que señala el principio de que el puntero de la matriz; la llamada printf("%p", x[0]) imprimirá el contenido de la memoria en las células marcadas como «dirección de la matriz».

    • x[0] no es la dirección de la matriz.
    • Sí, siguiendo la letra de la norma, x[0] no es la dirección de la matriz, es la propia matriz. He añadido una explicación detallada de este, y de por qué escribí que x[0] es la «dirección de la matriz». Espero que os guste.
    • impresionantes gráficos que explican perfectamente bien!
  4. 18
    • x[0] elimina referencias a la ultraperiféricas puntero (puntero a una matriz de tamaño 5 de puntero a int) y los resultados en una matriz de tamaño 5 de puntero a int;
    • x[0][0] elimina referencias a la ultraperiféricas puntero y los índices de la matriz, lo que resulta en un puntero a int;
    • x[0][0][0] elimina referencias a todo, lo que resulta en un valor concreto.

    Por cierto, si alguna vez se siente confundido por lo que este tipo de declaraciones decir, el uso de cdecl.

  5. 11

    Vamos a considerar el paso a paso de expresiones x[0], x[0][0] y x[0][0][0].

    Como x se definen de la siguiente manera

    int *(*x)[5];

    entonces la expresión x[0] es una matriz de tipo int *[5]. Tomar en cuenta que la expresión x[0] es equivalente a la expresión *x. Que es desreferenciar un puntero a una matriz obtenemos la matriz de sí mismo. Vamos a indicar como y es que tenemos una declaración

    int * y[5];

    Expresión x[0][0] es equivalente a y[0] y el tipo de int *. Vamos a denotar como z es que tenemos una declaración

    int *z;

    expresión x[0][0][0] es equivalente a la expresión y[0][0] que a su vez es equivalente a la expresión z[0] y el tipo de int.

    Así que hemos

    x[0] tiene el tipo int *[5]

    x[0][0] tiene el tipo int *

    x[0][0][0] tiene el tipo int

    Por lo que son objetos de diferentes tipos, y por la forma de diferentes tamaños.

    Ejecutar por ejemplo

    std::cout << sizeof( x[0] ) << std::endl;
    std::cout << sizeof( x[0][0] ) << std::endl;
    std::cout << sizeof( x[0][0][0] ) << std::endl;
  6. 10

    Primera cosa que tengo que decir que

    x [ 0 ] = * ( x + 0 ) = * x ;

    x [ 0 ] [ 0 ] = * ( * ( x + 0 ) + 0 ) = * * x ;

    x [ 0 ] [ 0 ] [ 0 ] = * ( * ( * ( x + 0 ) + 0 ) ) = * * * x ;

    Tan * x ≠ * * x ≠ * * * x

    De la siguiente imagen, todas las cosas están claras.

      x[0][0][0]= 2000
    
      x[0][0]   = 1001
    
      x[0]      = 10

    ¿Por qué es x[0] != x[0][0] != x[0][0][0]?

    Es sólo un ejemplo, en donde el valor de x[0][0][0]=10

    y la dirección de x[0][0][0] es 1001

    de que la dirección se almacena en x[0][0]=1001

    y la dirección de x[0][0] es 2000

    y que la dirección está almacenada en x[0]=2000

    Así x[0][0][0] x[0][0] x[0]

    .

    PELÍCULAS

    Programa 1:

    {
    int ***x;
    x=(int***)malloc(sizeof(int***));
    *x=(int**)malloc(sizeof(int**));
    **x=(int*)malloc(sizeof(int*));
    ***x=10;
    printf("%d   %d   %d   %d\n",x,*x,**x,***x);
    printf("%d   %d   %d   %d   %d",x[0][0][0],x[0][0],x[0],x,&x);
    }

    Salida

    142041096 142041112 142041128 10
    10 142041128 142041112 142041096 -1076392836

    Programa 2:

    {
    int x[1][1][1]={10};
    printf("%d   %d   %d   %d \n ",x[0][0][0],x[0][0],x[0],&x);
    }

    Salida

    10   -1074058436   -1074058436   -1074058436 
    • Su respuesta es engañosa. x[0] no contiene hormiga dirección. Su matriz. Para que no se descomponga a puntero a su primer elemento.
    • Ummm… ¿qué significa? Su edición es como la cereza en el pastel a su respuesta equivocada. No tiene sentido
    • Si se está usando punteros solos, esta respuesta será correcta. Habrá algunos cambios en la dirección de la sección cuando se utiliza la Matriz de
  7. 7

    Si usted fuera a ver las matrices a partir de una perspectiva del mundo real, parecería como así:

    x[0] es un contenedor de carga lleno de cajas.

    x[0][0] es una caja única, llena de cajas de zapatos, dentro del contenedor de carga.

    x[0][0][0] es una sola caja de zapatos dentro de la caja, en el interior del contenedor de carga.

    Incluso si se tratara de la única caja de zapatos en el único cajón en el contenedor de carga, es todavía una caja de zapatos y no un contenedor de carga

    • no x[0][0] ser una sola caja llena de pedazos de papel que tienen las ubicaciones de las cajas de zapatos escrito sobre ellos?
  8. 4

    Hay un principio en C++, de manera que: una declaración de una variable indica exactamente la forma de uso de la variable. Considere la posibilidad de su declaración:

    int *(*x)[5];

    que puede escribirse como (más clara):

    int *((*x)[5]);

    Debido al principio, tenemos:

    *((*x)[i]) is treated as an int value (i = 0..4)
     (*x)[i] is treated as an int* pointer (i = 0..4)
     *x is treated as an int** pointer
     x is treated as an int*** pointer

    Por lo tanto:

    x[0] is an int** pointer
     x[0][0] = (x[0]) [0] is an int* pointer
     x[0][0][0] = (x[0][0]) [0] is an int value

    Así que usted puede averiguar la diferencia.

    • x[0] es un conjunto de 5 enteros, no es un puntero. (se pueden decaer a un puntero en la mayoría de los contextos, pero la distinción es importante aquí).
    • Bien, pero usted debe decir: x[0] es una matriz de 5 punteros int*
    • Para dar la correcta derivación por @MattMcNabb: *(*x)[5] es un int, así (*x)[5] es un int *, así *x es un (int *)[5], así x es un *((int *)[5]). Es decir, x es un puntero a un 5-matriz de punteros a int.
  9. 2

    Ser p un puntero: estás apilamiento desreferencias con p[0][0], que es equivalente a *((*(p+0))+0).

    De referencia de C (&) y eliminar (*) notación:

    p == &p[0] == &(&p[0])[0] == &(&(&p[0])[0])[0])

    Es equivalente a:

    p == &*(p+0) == &*(&*(p+0))+0 == &*(&*(&*(p+0))+0)+0

    Mirada que, el &* puede ser refactorizado, sólo la eliminación de ella:

    p == p+0 == p+0+0 == p+0+0+0 == (((((p+0)+0)+0)+0)+0)
    • ¿Qué estás tratando de mostrar con todo después de su primera frase? Usted acaba de tener un montón de variaciones en p == p . &(&p[0])[0] es diferente a p[0][0]
    • El chico le preguntó por qué ‘x[0] != x[0][0] != x[0][0][0]’ cuando x es un puntero a la derecha ? He intentado mostrar que él puede ser atrapada por la C notación de eliminar la referencia (*) cuando se apilan [0]’s. Así, es una oportunidad para mostrarle la notación correcta para que x sea igual a x[0], haciendo referencia a x[0] de nuevo con &, y así sucesivamente.
  10. 1

    Usted está tratando de comparar diferentes tipos por valor

    Si usted toma las direcciones que usted puede conseguir más de lo que esperan

    Tenga en cuenta que su declaración que hace una diferencia

     int y [5][5][5];

    permitiría a las comparaciones que se desea, ya que y, y[0], y[0][0], y[0][0][0] que tienen diferentes valores y tipos, pero la misma dirección

    int **x[5];

    no ocupa espacio contiguo.

    x y x [0] tienen la misma dirección, pero x[0][0] y x[0][0][0] son, cada una en diferentes direcciones

    • int *(*x)[5] es diferente a int **x[5]
  11. 1

    Las otras respuestas son correctas, pero ninguno de ellos hacen hincapié en la idea de que es posible para todos los tres para contener el mismo valor, y por lo que están de alguna manera incompleta.

    La razón de que esto no puede ser entendido a partir de las otras respuestas es que todas las ilustraciones, si bien son útiles y sin duda razonable en la mayoría de los casos, no logran cubrir la situación en la que el puntero x se señala a sí mismo.

    Esto es bastante fácil de construir, pero, claramente, un poco más difícil de entender. En el siguiente programa, vamos a ver cómo nos puede obligar a todos los tres valores idénticos.

    NOTA: El comportamiento en este programa no está definido, pero voy a postear aquí únicamente como una interesante demostración de algo que los punteros puede hacer, pero no.

    #include <stdio.h>
    
    int main () {
      int *(*x)[5];
    
      x = (int *(*)[5]) &x;
    
      printf("%p\n", x[0]);
      printf("%p\n", x[0][0]);
      printf("%p\n", x[0][0][0]);
    }

    Esto compila sin advertencias en tanto C89 y C99, y el resultado es el siguiente:

    $ ./ptrs
    0xbfd9198c
    0xbfd9198c
    0xbfd9198c

    Curiosamente, los tres valores son idénticos. Pero esto no debería ser una sorpresa! En primer lugar, vamos a romper el programa.

    Declaramos x como un puntero a un array de 5 elementos, donde cada elemento es de tipo puntero a int. Esta declaración asigna 4 bytes en el tiempo de ejecución de la pila (o más, dependiendo de su aplicación; en mi máquina punteros son de 4 bytes), por lo que x se refiere a una ubicación de memoria real. En el C de la familia de las lenguas, el contenido de x son solo basura, algo que se deja de uso previo de la ubicación, por lo que x en sí no punto en cualquier lugar—desde luego no en el espacio asignado.

    Así que, naturalmente, se puede tomar la dirección de la variable x y ponerlo en algún lugar, así que eso es exactamente lo que hacemos. Pero vamos a seguir adelante y poner en x en sí mismo. Desde &x tiene un tipo diferente de x, tenemos que hacer una conversión para no obtener advertencias.

    El modelo de memoria sería algo como esto:

    0xbfd9198c
    +------------+
    | 0xbfd9198c |
    +------------+

    Por lo que el 4-byte del bloque de memoria en la dirección 0xbfd9198c contiene el patrón de bits correspondiente al valor hexadecimal 0xbfd9198c. Bastante Simple.

    Siguiente es la impresión de los tres valores. Las otras respuestas explicar lo que cada expresión se refiere, por lo que la relación debe ser claro ahora.

    Podemos ver que los valores son los mismos, pero sólo en un nivel muy bajo sentido…sus patrones de bits que son idénticos, pero el tipo de datos asociados con cada uno de los medios de expresión de sus interpretar los valores son diferentes.
    Por ejemplo, si queremos imprimir x[0][0][0] utilizando el formato de cadena de %d, obtendríamos un gran número negativo, por lo que los «valores» son, en la práctica, diferentes, pero el patrón de bits es el mismo.

    Esto es en realidad muy simple…en el diagrama, las flechas se acaba de apuntar a la misma dirección de memoria en lugar de a otros. Sin embargo, mientras que fueron capaces de forzar un resultado esperado de un comportamiento indefinido, es sólo que—indefinido. Este no es el código de producción, sino simplemente una manifestación en aras de la exhaustividad.

    En una razonable situación, usted tendrá que usar malloc para crear la matriz de 5 int punteros, y de nuevo para crear los enteros que están apuntados en la matriz. malloc siempre devuelve una dirección única (a menos que usted está fuera de la memoria, en cuyo caso se devuelve el valor NULL o 0), de modo que usted nunca tendrá que preocuparse acerca de la auto-referencial punteros como este.

    Esperemos que esa es la respuesta completa que usted está buscando. Usted no debe esperar a x[0], x[0][0], y x[0][0][0] a ser igual, pero que podría ser si se le obliga. Si algo pasaba por su cabeza, hágamelo saber para que yo pueda aclarar!

    • Yo diría que otro extraño uso de punteros que he visto nunca.
    • Sí, es bastante raro, pero cuando se puede romper hacia abajo, es tan básico como el resto de los ejemplos. Sólo pasa a ser un caso en el que los patrones de bits que son todos de la misma.
    • El código hace que un comportamiento indefinido . x[0] en realidad no representan un objeto válido del tipo correcto
    • ES indefinido, y tengo muy claro que en realidad. No estoy de acuerdo sobre el tipo. x es un puntero a un array, por lo que podemos utilizar la [] operador especificar un desplazamiento de ese puntero y eliminar la referencia de la misma. Lo extraño no? El resultado de x[0] es una matriz, y C no se queja si usted la impresión de que el uso de %p ya que es cómo se implementa debajo de todos modos.
    • Y la compilación de este con el -pedantic bandera no produce advertencias, por lo que C está muy bien con los tipos de…
    • ninguna advertencia no significa que el código es correcto. Si usted no ha colado un error. El yeso sólo hace que el compilador de ocultar el mensaje, no soluciona el código
    • x[0] sólo funciona si la ubicación de la memoria señalado por x contiene un objeto de la clase que x es un puntero a. En el código no. Es el mismo error como int j; float *x = (float *)&j; foo(x[0]);. Que las reglas del lenguaje C. Personas que se enteraron por C ensayo y error podría haber pasado por alto esta regla.
    • Ah, entiendo tu punto de vista @MattMcNabb. Tienes toda la razón, pero creo que soy claro en decir que este es un comportamiento indefinido y es simplemente la dirección de la idea de que ellos no pueden ser el mismo. Mientras que los tipos son bastante descompone aquí creo que es una interesante demostración. Debo agregar un descargo de responsabilidad más grande?
    • No veo donde diga que es un comportamiento indefinido. Usted menciona que x[0] podría contener la basura en una sola frase, pero el resto de su respuesta, habla como si x[0] ha definido el contenido. Por ejemplo, «pero que realmente podría ser.» – en el hecho de que absolutamente no podía ser. Usted puede aparecen para obtener los resultados que se parecen a los valores son los mismos, sólo si usted escribe un programa que tiene un comportamiento indefinido. Lo que realmente no es decir nada, ya que se puede producir alguna el resultado de un comportamiento indefinido. En C un puntero puede apuntar a sí mismo y se eliminan las referencias.
    • en el tercero a último párrafo, me dicen que es «totalmente indefinido.» Además, x ha definido el contenido cuando asignamos un valor a la misma. Pero, si usted cree que esta respuesta va a causar más confusión, puedo eliminarlo y tal vez volver a ella en un tiempo. 🙂
    • «lo que funciona» y «es totalmente indefinido» son incompatibles. Tu post es muy interesante, pero creo que se podría mejorar señalando a la derecha hasta donde primero hacer el elenco que todo lo que sigue no está cubierto por el C estándar.
    • He editado la respuesta, quisiera saber si me puede hacer más para mejorar! 🙂

Dejar respuesta

Please enter your comment!
Please enter your name here