18 Pregunta: Con matrices, ¿por qué es un caso que un [5] == 5 [a]?

pregunta creada en Sun, Oct 21, 2018 12:00 AM

Como señala Joel en Podcast de desbordamiento de pila # 34 , en Lenguaje de programación C (también conocido como: K & R), se menciona esta propiedad de matrices en C: a[5] == 5[a]

Joel dice que es debido a la aritmética de punteros, pero todavía no entiendo. ¿Por qué a[5] == 5[a] ?

    
1527
  1. ¿algo como un [+] también funcionaría como * (a ++) OR * (++ a)?
    2010-05-13 16: 14: 09Z
  2. @ Egon: Eso es muy creativo pero desafortunadamente no es así como funcionan los compiladores. El compilador interpreta a[1] como una serie de tokens, no cadenas: * ({ubicación entera de} a {operador} + {entero} 1) es lo mismo que * ({integer} 1 {operador} + {ubicación entera de} a ) pero no es lo mismo que * ({ubicación de entero de} a {operator} + {operator} +)
    2010-05-13 17: 24: 52Z
  3. Una variación compuesta interesante sobre esto se ilustra en acceso a la matriz ilógica , donde tiene char bar[]; int foo[]; y foo[i][bar] se usa como una expresión.
    2012-10-17 06: 38: 19Z
  4. @ EldritchConundrum, ¿por qué crees que 'el compilador no puede verificar que la parte izquierda es un puntero'? Sí puede. Es cierto que a[b] = *(a + b) para cualquier a y b, pero fue la elección libre de los diseñadores de idiomas para + que se definirá como conmutativa para todos los tipos. Nada podría impedirles prohibir i + p mientras permiten p + i.
    2014-03-14 19: 46: 59Z
  5. @ Andrey One generalmente espera que el + sea conmutativo, por lo que tal vez el verdadero problema sea hacer que las operaciones del puntero se parezcan a la aritmética, en lugar de diseñar un operador de desplazamiento separado. >
    2014-03-18 10: 36: 58Z
    18 Respuestas                              18                         

    El estándar C define el operador [] de la siguiente manera:

    a[b] == *(a + b)

    Por lo tanto, a[5] evaluará a:

     
    *(a + 5)
    

    y 5[a] evaluarán a:

     
    *(5 + a)
    

    a es un puntero al primer elemento de la matriz. a[5] es el valor que es 5 elementos más allá de a, que es el mismo que *(a + 5), y de la escuela primaria sabemos que son iguales (la suma es commutative ).

        
    1821
    2016-11-30 10: 47: 52Z
    1. Me pregunto si no se parece más a * ((5 * sizeof (a)) + a). Gran explicación aunque.
      2008-12-19 17: 06: 42Z
    2. @ Dinah: Desde la perspectiva del compilador C, tienes razón. No se necesita sizeof y las expresiones que mencioné son las MISMAS. Sin embargo, el compilador tendrá en cuenta sizeof al producir código de máquina. Si a es una matriz int, a[5] se compilará en algo así como mov eax, [ebx+20] en lugar de [ebx+5]
      2008-12-19 17: 18: 23Z
    3. @ Dinah: A es una dirección, digamos 0x1230. Si a estaba en una matriz int de 32 bits, entonces un [0] está en 0x1230, un [1] está en 0x1234, un [2] en 0x1238 ... a [5] en x1244, etc. Si solo agregamos 5 a 0x1230, obtenemos 0x1235, lo cual es incorrecto.
      2008-12-19 17: 21: 39Z
    4. @ sr105: Este es un caso especial para el operador +, donde uno de los operandos es un puntero y el otro un entero. El estándar dice que el resultado será del tipo del puntero. El compilador /tiene que ser /suficientemente inteligente.
      2008-12-23 02: 08: 05Z
    5. "de la escuela primaria. Sabemos que son iguales". Entiendo que está simplificando, pero estoy con quienes sienten que esto es sobre simplificando. No es elemental que *(10 + (int *)13) != *((int *)10 + 13). En otras palabras, aquí hay más cosas que la aritmética de la escuela primaria. La conmutabilidad se basa fundamentalmente en que el compilador reconozca qué operando es un puntero (y con qué tamaño de objeto). Para decirlo de otra manera, (1 apple + 2 oranges) = (2 oranges + 1 apple), pero (1 apple + 2 oranges) != (1 orange + 2 apples).
      2010-12-01 20: 54: 34Z

    Porque el acceso a la matriz se define en términos de punteros. a[i] se define como *(a + i), que es conmutativo.

        
    278
    2011-05-13 13: 47: 10Z
    1. Las matrices no se definen en términos de punteros, pero acceder a ellos es.
      2011-05-12 23: 20: 41Z
    2. Agregaría "por lo que es igual a *(i + a), que puede escribirse como i[a]".
      2013-04-05 22: 11: 18Z
    3. Le sugiero que incluya la cita de la norma, que es la siguiente: 6.5.2.1: 2 Una expresión de posfijo seguida de una expresión entre corchetes [] es una Designación en subíndice de un elemento de un objeto de matriz. La definición del operador de subíndice [] es que E1 [E2] es idéntico a (* ((E1) + (E2))). Debido a las reglas de conversión que se aplican al operador binario +, si E1 es un objeto de matriz (de manera equivalente, un puntero al elemento inicial de un objeto de matriz) y E2 es un número entero, E1 [E2] designa el elemento E2-th de E1 (contando desde cero).
      2015-02-17 21: 41: 13Z
    4. Para ser más correctos: las matrices se convierten en punteros cuando se accede a ellos.
      2018-05-14 16: 11: 00Z

    Creo que las otras respuestas están perdiendo algo.

    Sí, p[i] es por definición equivalente a *(p+i), que (debido a que la suma es conmutativa) es equivalente a *(i+p), que (de nuevo, por la definición del operador []) es equivalente a i[p].

    (Y en array[i], el nombre de la matriz se convierte implícitamente en un puntero al primer elemento de la matriz).

    Pero la conmutación de la adición no es tan obvia en este caso.

    Cuando ambos operandos son del mismo tipo, o incluso de diferentes tipos numéricos que se promueven a un tipo común, la conmutatividad tiene mucho sentido: x + y == y + x.

    Pero en este caso estamos hablando específicamente de aritmética de punteros, donde un operando es un puntero y el otro es un entero. (Entero + entero es una operación diferente, y puntero + puntero no tiene sentido).

    La descripción de la norma C del operador + ( N1570 6.5) .6) dice:

      

    Para la adición, ambos operandos tendrán un tipo aritmético, o uno   El operando será un puntero a un tipo de objeto completo y el otro   tendrá tipo entero.

    Se podría haber dicho tan fácilmente:

      

    Además, ambos operandos tendrán un tipo aritmético o la izquierda   El operando debe ser un puntero a un tipo de objeto completo y el operando derecho   tendrá tipo entero.

    en cuyo caso, tanto i + p como i[p] serían ilegales.

    En términos de C ++, realmente tenemos dos conjuntos de + operadores sobrecargados, que se pueden describir de forma general como:

     
    pointer operator+(pointer p, integer i);
    

    y

     
    pointer operator+(integer i, pointer p);
    

    de los cuales solo el primero es realmente necessary.

    Entonces, ¿por qué es así?

    C ++ heredó esta definición de C, que la obtuvo de B (la conmutabilidad de la indexación de matrices se menciona explícitamente en 1972 Referencia del usuario a B ), que lo obtuvo de BCPL (manual con fecha de 1967), que bien puede haberlo obtenido de idiomas anteriores (CPL? Algol?).

    Entonces, la idea de que la indexación de matrices se define en términos de adición, y esa adición, incluso de un puntero y un entero, es conmutativa, se remonta muchas décadas, a las lenguas ancestrales de C.

    Esos lenguajes estaban mucho menos tipificados que el C moderno. En particular, la distinción entre punteros y enteros a menudo se ignoraba. (Los programadores tempranos de C a veces usaban punteros como enteros sin signo, antes de que la palabra clave unsigned se agregara al lenguaje). Por lo tanto, la idea de hacer una adición no conmutativa porque los operandos son de diferentes tipos probablemente no se les habría ocurrido a los diseñadores de esos lenguajes. . Si un usuario quería agregar dos "cosas", ya sea que esas "cosas" sean enteros, punteros o alguna otra cosa, no era el idioma adecuado para evitarlo.

    Y a lo largo de los años, cualquier cambio en esa regla habría roto el código existente (aunque el estándar ANSI C de 1989 podría haber sido una buena oportunidad).

    Cambiar C y /o C ++ para que sea necesario colocar el puntero a la izquierda y el entero a la derecha podría romper algún código existente, pero no habría pérdida del poder expresivo real.

    Ahora tenemos arr[3] y 3[arr] que significan exactamente lo mismo, aunque la última forma nunca debe aparecer fuera de IOCCC .

        
    212
    2016-01-28 20: 48: 59Z
    1. Descripción fantástica de esta propiedad. Desde un punto de vista de alto nivel, creo que 3[arr] es un artefacto interesante, pero rara vez debería usarse. La respuesta aceptada a esta pregunta (< stackoverflow.com/q/1390365/356> ) que le pregunté un rato La espalda ha cambiado la forma en que he pensado acerca de la sintaxis. Aunque a menudo técnicamente no hay una forma correcta e incorrecta de hacer estas cosas, este tipo de características lo hacen pensar de una manera que está separada de los detalles de la implementación. Esta forma diferente de pensar tiene beneficios que se pierden en parte al fijarse en los detalles de la implementación.
      2013-08-24 01: 01: 54Z
    2. La adición es conmutativa. Para el estándar C, definirlo de lo contrario sería extraño. Es por eso que no se puede decir tan fácilmente "Para la adición, ambos operandos tendrán un tipo aritmético, o el operando izquierdo será un puntero a un tipo de objeto completo y el operando derecho tendrá un tipo entero". - Eso no tendría sentido para la mayoría de las personas que agregan cosas.
      2014-04-21 17: 54: 14Z
    3. @ iheanyi: la adición suele ser conmutativa, y generalmente toma dos operandos del mismo tipo. La adición de puntero le permite agregar un puntero y un entero, pero no dos punteros. En mi humilde opinión, ya es un caso especial lo suficientemente extraño como para exigir que el puntero sea el operando izquierdo no sería una carga significativa. (Algunos idiomas usan "+" para la concatenación de cadenas; ciertamente no es conmutativo).
      2014-04-21 18: 13: 58Z
    4. @ supercat, eso es aún peor. Eso significaría que a veces x + 1! = 1 + x. Eso violaría completamente la propiedad asociativa de la adición.
      2014-10-21 16: 34: 59Z
    5. @ iheanyi: Creo que quisiste decir propiedad conmutativa; la adición ya no es asociativa, ya que en la mayoría de las implementaciones (1LL + 1U) -2! = 1LL + (1U-2). De hecho, el cambio haría asociativas algunas situaciones que actualmente no lo son, por ejemplo. 3U + (UINT_MAX-2L) sería igual a (3U + UINT_MAX) -2. Lo que sería mejor, sin embargo, es que el lenguaje agregue nuevos tipos distintos para enteros promuevebles y "envuelva" anillos algebraicos, de modo que al agregar 2 a un ring16_t que tiene 65535 se obtendría un ring16_t con valor 1, independiente de el tamaño de int .
      2014-10-21 16: 46: 00Z

    Y, por supuesto

     
     ("ABCD"[2] == 2["ABCD"]) && (2["ABCD"] == 'C') && ("ABCD"[2] == 'C')
    

    La razón principal de esto fue que en la década de los 70 cuando se diseñó C, las computadoras no tenían mucha memoria (64KB era mucho), por lo que el compilador de C no hizo mucha comprobación de sintaxis. Por lo tanto, "X[Y]" fue traducido a ciegas a "*(X+Y)"

    Esto también explica las sintaxis "+=" y "++". Todo en la forma "A = B + C" tenía la misma forma compilada. Pero, si B era el mismo objeto que A, entonces estaba disponible una optimización de nivel de ensamblaje. Pero el compilador no era lo suficientemente brillante como para reconocerlo, por lo que el desarrollador tuvo que hacerlo (A += C). De manera similar, si C era 1, estaba disponible una optimización de nivel de ensamblaje diferente, y nuevamente el desarrollador tuvo que hacerlo explícito, porque el compilador no lo reconoció. (Los compiladores más recientes lo hacen, por lo que esas sintaxis son en gran medida innecesarias en estos días)

        
    191
    2017-07-28 17: 51: 58Z
    1. En realidad, eso se evalúa como falso; el primer término "ABCD" [2] == 2 ["ABCD"] se evalúa como verdadero, o 1, y 1! = 'C': D
      2008-12-19 17: 16: 12Z
    2. @ Jonathan: la misma ambigüedad llevó a la edición del título original de esta publicación. Somos equivalentes matemáticos, sintaxis de código o pseudocódigo. Discuto la equivalencia matemática pero ya que estamos hablando de código, no podemos escapar de que estamos viendo todo en términos de sintaxis de código.
      2008-12-19 17: 26: 03Z
    3. ¿No es esto un mito? Quiero decir que los operadores + = y ++ fueron creados para simplificar para el compilador? Algunos códigos se vuelven más claros con ellos, y es útil tener una sintaxis, sin importar lo que el compilador haga con ellos.
      2008-12-19 17: 44: 13Z
    4. + = y ++ tiene otro beneficio significativo. Si el lado izquierdo cambia alguna variable mientras se evalúa, el cambio solo se realizará una vez. a = a + ...; Lo haré dos veces.
      2008-12-19 17: 49: 27Z
    5. No - "ABCD" [2] == * ("ABCD" + 2) = * ("CD") = 'C'. Dereferencia de una cadena te da un carácter, no una subcadena
      2009-09-21 10: 34: 38Z

    Una cosa que nadie parece haber mencionado sobre el problema de Dinah con el sizeof:

    Solo puede agregar un entero a un puntero, no puede agregar dos punteros juntos. De esa manera, cuando se agrega un puntero a un entero o un entero a un puntero, el compilador siempre sabe qué bit tiene un tamaño que se debe tener en cuenta.

        
    52
    2009-12-18 08: 01: 42Z
    1. Hay una conversación bastante exhaustiva sobre esto en los comentarios de la respuesta aceptada. Hice referencia a dicha conversación en la edición a la pregunta original, pero no abordé directamente su preocupación muy válida de sizeof. No estoy seguro de cómo hacerlo mejor en SO. Debo hacer otra edición al original. pregunta?
      2009-04-21 13: 51: 49Z

    Para responder a la pregunta literalmente. No siempre es cierto que x == x

     
    double zero = 0.0;
    double a[] = { 0,0,0,0,0, zero/zero}; // NaN
    cout << (a[5] == 5[a] ? "true" : "false") << endl;
    

    impresiones

     
    false
    
        
    47
    2011-08-11 13: 50: 22Z
    1. En realidad, "nan" no es igual a sí mismo: cout << (a[5] == a[5] ? "true" : "false") << endl; es false.
      2013-04-23 09: 34: 43Z
    2. @ TrueY: Él indicó que específicamente para el caso de NaN (y específicamente que x == x no siempre es cierto). Creo que esa era su intención. Así que él está técnicamente correcto (y posiblemente, como dicen, ¡el mejor tipo de correcto!).
      2015-02-13 01: 04: 07Z
    3. La pregunta es acerca de C, su código no es el código C. También hay un NAN en <math.h>, que es mejor que 0.0/0.0, porque 0.0/0.0 es UB cuando __STDC_IEC_559__ no está definido (la mayoría de las implementaciones no definen __STDC_IEC_559__, pero en la mayoría de las 0.0/0.0 aún funcionará)
      2018-05-14 16: 02: 41Z

    Buenas preguntas /respuestas.

    Solo quiero señalar que los punteros C y las matrices no son iguales , aunque en este caso la diferencia no es esencial.

    Considere las siguientes declaraciones:

     
    int a[10];
    int* p = a;
    

    En a.out , el símbolo a está en una dirección que es el comienzo de la matriz, y el símbolo p está en una dirección donde se almacena un puntero, y el valor del puntero en esa ubicación de memoria es el comienzo de la matriz.

        
    23
    2008-12-20 08: 16: 20Z
    1. No, técnicamente no son lo mismo. Si define alguna b como int * const y hace que apunte a una matriz, sigue siendo un puntero, lo que significa que en la tabla de símbolos, b se refiere a una ubicación de memoria que almacena una dirección, que a su vez apunta a donde está la matriz .
      2008-12-22 05: 42: 16Z
    2. Muy buen punto. Recuerdo que tuve un error muy desagradable cuando definí un símbolo global como caracteres s [100] en un módulo, declararlo como caracteres externos *; en otro modulo. Después de vincularlo todo, el programa se comportó de manera muy extraña. Debido a que el módulo que usa la declaración externa usaba los bytes iniciales de la matriz como puntero a char.
      2012-05-02 18: 15: 33Z
    3. Originalmente, en el abuelo de C de BCPL, una matriz era un puntero. Es decir, lo que obtuvo cuando escribió (transliteré a C) int a[10] fue un puntero llamado 'a', que apuntaba a un almacenamiento suficiente para 10 enteros, en otros lugares. Por lo tanto, a + i y j + i tenían la misma forma: agregar el contenido de un par de ubicaciones de memoria. De hecho, creo que el BCPL era tipográfico, por lo que eran idénticos. Y la escala de tamaño del tipo no se aplicó, ya que BCPL estaba puramente orientado a la palabra (en máquinas con direcciones de palabra también).
      2012-05-03 02: 33: 10Z
    4. Creo que la mejor manera de entender la diferencia es comparar int*p = a; con int b = 5;. En este último, "b" y "5" son enteros, pero "b" es una variable, mientras que "5" es un valor fijo. Del mismo modo, "p" & "a" son las dos direcciones de un carácter, pero "a" es un valor fijo.
      2013-03-12 16: 34: 28Z

    Acabo de descubrir que esta fea sintaxis podría ser "útil", o al menos muy divertida para jugar cuando se quiere tratar con una matriz de índices que se refieren a posiciones en la misma matriz. Puede reemplazar los corchetes anidados y hacer que el código sea más legible.

     
    int a[] = { 2 , 3 , 3 , 2 , 4 };
    int s = sizeof a / sizeof *a;  //  s == 5
    
    for(int i = 0 ; i < s ; ++i) {  
    
               cout << a[a[a[i]]] << endl;
               // ... is equivalent to ... 
               cout << i[a][a][a] << endl;  // but I prefer this one, it's easier to increase the level of indirection (without loop)
    
    }
    

    Por supuesto, estoy bastante seguro de que no hay ningún caso de uso en el código real, pero de todos modos me pareció interesante :)

        
    22
    2012-06-10 19: 50: 54Z
    1. ¡Oh Dios! ¿Cómo puede alguien decir que prefiere esa notación? ¡Me duele la vista!
      2014-09-19 13: 14: 49Z
    2. Cuando ve i[a][a][a], cree que es un puntero a una matriz o una matriz de un puntero a una matriz o una matriz ... y a es un índice. Cuando ve a[a[a[i]]], cree que a es un puntero a una matriz o una matriz y i es un índice.
      2018-05-14 11: 58: 02Z
    3. ¡Wow! Es muy bueno el uso de esta característica "estúpida". Podría ser útil en concurso algorítmico en algunos problemas))
      2018-06-28 08: 53: 18Z

    Para los punteros en C, tenemos

     
    a[5] == *(a + 5)
    

    y también

     
    5[a] == *(5 + a)
    

    Por lo tanto, es cierto que a[5] == 5[a].

        
    18
    2012-03-23 ​​17: 36: 57Z

    No es una respuesta, solo es algo para pensar. Si la clase tiene un operador de índice /subíndice sobrecargado, la expresión 0[x] no funcionará:

     
    class Sub
    {
    public:
        int operator [](size_t nIndex)
        {
            return 0;
        }   
    };
    
    int main()
    {
        Sub s;
        s[0];
        0[s]; // ERROR 
    }
    

    Como no tenemos acceso a la clase int , esto no se puede hacer:

     
    class int
    {
       int operator[](const Sub&);
    };
    
        
    14
    2015-12-09 18: 29: 15Z
    1. class Sub { public: int operator[](size_t nIndex) const { return 0; } friend int operator[](size_t nIndex, const Sub& This) { return 0; } };
      2013-04-05 17: 23: 11Z
    2. ¿Realmente has intentado compilarlo? ¡Hay un conjunto de operadores que no se pueden implementar fuera de la clase (es decir, como funciones no estáticas)!
      2013-04-05 21: 10: 03Z
    3. Vaya, tienes razón. "operator[] será una función miembro no estática con exactamente un parámetro". Estaba familiarizado con esa restricción en operator=, no creía que se aplicara a [].
      2013-04-05 21: 21: 37Z
    4. Por supuesto, si cambia la definición de operador [], nunca volvería a ser equivalente ... si a[b] es igual a *(a + b) y cambia esto, podrá También hay que sobrecargar int::operator[](const Sub&); y int no es una clase ...
      2014-09-19 13: 18: 17Z
    5. Esto ... no es ... C.
      2016-12-13 07: 13: 46Z

    Tiene una muy buena explicación en UN TUTORIAL SOBRE PUNTOS Y ARRAYS EN C por Ted Jensen.

    Ted Jensen lo explicó como:

      

    De hecho, esto es cierto, es decir, donde se escriba a[i] puede ser   Reemplazado con *(a + i) sin ningún problema. De hecho, el compilador   Creará el mismo código en cualquier caso. Así vemos ese puntero.   La aritmética es lo mismo que la indexación de matrices. Cualquiera de las dos sintaxis produce   el mismo resultado.

         

    Esto NO está diciendo que los punteros y matrices   son lo mismo, no lo son. Solo estamos diciendo que para identificar   un elemento dado de una matriz tenemos la opción de dos sintaxis, una   utilizando la indexación de matrices y la otra aritmética de puntero, que   producir resultados idénticos.

         

    Ahora, mirando esto último   expresión, parte de ella .. (a + i), es una adición simple usando el +   operador y las reglas de C establecen que tal expresión es   conmutativo Es decir (a + i) es idéntico a (i + a). Así podríamos   escribe *(i + a) tan fácilmente como *(a + i).   ¡Pero *(i + a) podría haber venido de i[a]! De todo esto viene el curioso.   verdad que si:

     
    char a[20];
    
         

    escribiendo

     
    a[3] = 'x';
    
         

    es lo mismo que escribir

     
    3[a] = 'x';
    
        
    9
    2017-01-13 06: 00: 35Z
    1. a + i NO es una adición simple, porque es una aritmética de punteros. si el size del elemento a es 1 (char), entonces sí, es como entero +. Pero si es (por ejemplo) un entero, entonces podría ser equivalente a un + 4 * i.
      2015-12-04 20: 17: 46Z
    2. @ AlexBrown Sí, es una aritmética de punteros, que es exactamente la razón por la que su última oración es incorrecta, a menos que primero emita 'a' para ser un (char *) (suponiendo que un int es de 4 caracteres). Realmente no entiendo por qué tanta gente se está quedando obsesionada con el valor real resultante de la aritmética de punteros. El propósito completo de Pointer arithmetic es abstraer los valores de puntero subyacentes y dejar que el programador piense en los objetos que están siendo manipulados en lugar de los valores de dirección.
      2018-03-21 16: 11: 28Z

    Sé que la pregunta está respondida, pero no pude resistirme a compartir esta explicación.

    Recuerdo los principios del diseño del compilador, Supongamos que a es una matriz int y el tamaño de int es de 2 bytes, &amperio; La dirección base para a es 1000.

    Cómo funcionará a[5] - >

     
    Base Address of your Array a + (5*size of(data type for array a))
    i.e. 1000 + (5*2) = 1010
    

    Entonces,

    De manera similar, cuando el código c se divide en código de 3 direcciones,  5[a] se convertirá en - >

     
    Base Address of your Array a + (size of(data type for array a)*5)
    i.e. 1000 + (2*5) = 1010 
    

    Básicamente, ambas declaraciones apuntan a la misma ubicación en la memoria y, por lo tanto, a[5] = 5[a].

    Esta explicación es también la razón por la que los índices negativos en matrices funcionan en C.

    es decir, si accedo a a[-5] me lo dará

     
    Base Address of your Array a + (-5 * size of(data type for array a))
    i.e. 1000 + (-5*2) = 990
    

    Me devolverá el objeto en la ubicación 990.

        
    6
    2016-11-29 01: 18: 48Z

    En Arrays C , arr[3] y 3[arr] son iguales , y sus notaciones de puntero equivalentes son *(arr + 3) a *(3 + arr). Pero, por el contrario, [arr]3 o [3]arr no es correcto y generará un error de sintaxis, ya que (arr + 3)* y (3 + arr)* no son expresiones válidas. El motivo es que el operador debe colocarse antes de la dirección proporcionada por la expresión, no después de la dirección.

        
    5
    2013-12-17 11: 22: 08Z

    en c compilador

     
    a[i]
    i[a]
    *(a+i)
    

    son diferentes maneras de referirse a un elemento en una matriz. (NO EN TODO LO MISMO)

        
    4
    2014-10-29 09: 14: 54Z

    Un poco de historia ahora. Entre otros idiomas, el BCPL tuvo una influencia bastante importante en el desarrollo temprano de C. Si declaraste una matriz en BCPL con algo como:

     
    let V = vec 10
    

    que en realidad asignó 11 palabras de memoria, no 10. Normalmente, V fue la primera, y contenía la dirección de la palabra inmediatamente siguiente. Así que, a diferencia de C, la denominación V fue a esa ubicación y recogió la dirección del elemento cero de la matriz. Por lo tanto, la indirección de matriz en BCPL, expresada como

     
    let J = V!5
    

    realmente tenía que hacer J = !(V + 5) (usando la sintaxis BCPL) ya que era necesario obtener V para obtener la dirección base de la matriz. Así, V!5 y 5!V fueron sinónimos. Como observación anecdótica, WAFL (Warwick Functional Language) fue escrito en BCPL, y en mi mejor memoria tendía a usar la última sintaxis en lugar de la primera para acceder a los nodos utilizados como almacenamiento de datos. Concedido esto es de algún lugar entre hace 35 y 40 años, así que mi memoria está un poco oxidada. :)

    La innovación de prescindir de la palabra adicional de almacenamiento y hacer que el compilador inserte la dirección base de la matriz cuando fue nombrada vino más tarde. De acuerdo con el documento de historial de C, esto sucedió aproximadamente cuando se agregaron las estructuras a C.

    Tenga en cuenta que ! en BCPL era tanto un operador de prefijo unario como un operador de infijo binario, en ambos casos haciendo direccionamiento indirecto. solo que la forma binaria incluía una adición de los dos operandos antes de hacer el direccionamiento indirecto. Dada la naturaleza orientada a las palabras de BCPL (y B) esta realidadTiene mucho sentido. La restricción de "puntero y entero" se hizo necesaria en C cuando ganó tipos de datos, y sizeof se convirtió en una cosa.

        
    1
    2019-04-08 18: 45: 49Z

    En C

     
     int a[]={10,20,30,40,50};
     int *p=a;
     printf("%d\n",*p++);//output will be 10
     printf("%d\n",*a++);//will give an error
    

    El puntero es una "variable"

    el nombre de la matriz es un "mnemónico" o "sinónimo"

    p++; es válido pero a++ no es válido

    a[2] es igual a 2 [a] porque la operación interna en ambos es

    "Aritmética de punteros" calculada internamente como

    *(a+3) es igual a *(3+a)

        
    0
    2018-01-07 09: 49: 53Z

    Bueno, esta es una característica que solo es posible debido al soporte de idioma.

    El compilador interpreta a[i] como *(a+i) y la expresión 5[a] se evalúa como *(5+a). Como la suma es conmutativa, resulta que ambos son iguales. De ahí que la expresión se evalúe como true.

        
    0
    2018-04-02 18: 42: 27Z

    tipos de punteros

    1) puntero a los datos

     
    int *ptr;
    

    2) puntero constante a los datos

     
    int const *ptr;
    

    3) puntero de const a datos const.

     
    int const *const ptr;
    

    y las matrices son tipo de (2) de nuestra lista
    Cuando define una matriz a la vez, se inicializa una dirección en ese puntero
    Como sabemos, no podemos cambiar ni modificar el valor de const en nuestro programa porque genera un ERROR en el momento de compilación

    La diferencia principal que encontré es ...

    Podemos reinicializar el puntero con una dirección, pero no con el mismo caso de una matriz.

    ======
    y de vuelta a tu pregunta ...
    a [5] no es más que * (a + 5)
    que puedes entender fácilmente por
    a - la dirección que contiene (la gente la llama como dirección base) como un (2) tipo de puntero en nuestra lista
    [] - ese operador puede ser reemplazable con el puntero *.

    así que finalmente ...

     
    a[5] == *(a +5) == *(5 + a) == 5[a] 
    
        
    - 3
    2018-07-13 07: 34: 11Z
    1. Las matrices no son punteros.
      2018-10-02 05: 06: 02Z
fuente colocada aquí