Aritmética de punteros y matrices: ¿qué es realmente legal?

Considere las siguientes afirmaciones:

int *pFarr, *pVarr; int farr[3] = {11,22,33}; int varr[3] = {7,8,9}; pFarr = &(farr[0]); pVarr = varr; 

En esta etapa, ambos punteros apuntan al inicio de cada dirección de matriz respectiva. Para * pFarr, actualmente estamos mirando 11 y para * pVarr, 7.

Igualmente, si solicito el contenido de cada matriz a través de * farr y * varr, también obtengo 11 y 7.

Hasta ahora tan bueno.

Ahora, pFarr++ y pVarr++ . Genial. Ahora estamos mirando 22 y 8, como se esperaba.

Pero ahora…

varr++ subir farr++ y varr++ … y obtenemos “tipo de argumento incorrecto para incrementar”.

Ahora, reconozco la diferencia entre un puntero de matriz y un puntero regular, pero dado que su comportamiento es similar, ¿por qué esta limitación?

Esto me confunde aún más cuando también considero que en el mismo progtwig puedo llamar a la siguiente función de una manera aparentemente correcta y de otra manera incorrecta, y tengo el mismo comportamiento, aunque en contraste con lo que sucedió en el código publicado anteriormente !?

 working_on_pointers ( pFarr, farr ); // calling with expected parameters working_on_pointers ( farr, pFarr ); // calling with inverted parameters 

.

 void working_on_pointers ( int *pExpect, int aExpect[] ) { printf("%i", *pExpect); // displays the contents of pExpect ok printf("%i", *aExpect); // displays the contents of aExpect ok pExpect++; // no warnings or errors aExpect++; // no warnings or errors printf("%i", *pExpect); // displays the next element or an overflow element (with no errors) printf("%i", *aExpect); // displays the next element or an overflow element (with no errors) } 

¿Podría alguien ayudarme a entender por qué los punteros de matriz y los punteros se comportan de manera similar en algunos contextos, pero diferentes en otros?

Muchas gracias.

EDITAR: Noobs como yo podrían beneficiarse aún más de este recurso: http://www.panix.com/~elflord/cpp/gotchas/index.shtml

La diferencia se debe a que para que farr++ tenga algún efecto, en algún lugar el comstackdor necesitaría almacenar ese farr evaluará la dirección del segundo elemento de la matriz. Pero no hay lugar para esa información. El comstackdor solo asigna lugar para 3 enteros.

Ahora, cuando declara que un parámetro de función es una matriz, el parámetro de función no será una matriz. El parámetro de función será un puntero. No hay parámetros de matriz en C. Así que las siguientes dos declaraciones son equivalentes

 void f(int *a); void f(int a[]); 

Ni siquiera importa qué número se pone entre paréntesis, ya que el parámetro realmente será un puntero, el “tamaño” simplemente se ignora.

Esto es lo mismo para las funciones; los dos siguientes son equivalentes y tienen un puntero a función como parámetro:

 void f(void (*p)()); void f(void p()); 

Si bien puede llamar tanto un puntero a una función como una función (por lo que se usan de manera similar), tampoco podrá escribir en una función, porque no es un puntero, simplemente se convierte en un puntero:

 f = NULL; // error! 

De la misma manera no se puede modificar una matriz.

En C, no se puede asignar a matrices. Entonces, dado:

 T data[N]; 

donde T es un tipo y N es un número, no puedes decir:

 data = ...; 

Dado lo anterior, y que los data++; está tratando de asignar a los data , se obtiene el error.

Hay una regla simple en C sobre matrices y punteros. Es que, en contextos de valor, el nombre de una matriz es equivalente a un puntero a su primer elemento, y en contextos de objeto, el nombre de una matriz es equivalente a una matriz.

El contexto de objeto es cuando toma el tamaño de una matriz utilizando sizeof , o cuando toma su dirección ( &data ), o en el momento de la inicialización de una matriz. En todos los demás contextos, estás en un contexto de valor. Esto incluye pasar una matriz a una función.

Por lo tanto, su función:

 void working_on_pointers ( int *pExpect, int aExpect[] ) { 

es equivalente a

 void working_on_pointers ( int *pExpect, int *aExpect ) { 

La función no puede saber si se pasó una matriz o un puntero, ya que todo lo que ve es un puntero.

Hay más detalles en las respuestas a las siguientes preguntas:

  • tipo de una matriz ,
  • sizeof comportarse inesperadamente ,

También vea esta parte del sitio web de C for smarties , que está muy bien escrito.

Intentar incrementar farr o varr falla porque ninguno de los dos es un puntero. Cada uno es una matriz. El nombre de una matriz, cuando se evalúa solo (excepto como el operando del operador size o address-of) se evalúa a un valor (un valor de r) que es del tipo correcto que se asignará a un puntero. Intentar incrementarlo es un poco como intentar incrementar 17 . Puede incrementar un int que contenga el valor 17, pero el incremento de 17 no funcionará. El nombre de una matriz es bastante parecido a eso.

En cuanto a la segunda parte, es bastante simple: si intenta declarar un parámetro de función de tipo de matriz, el comstackdor lo “ajusta” silenciosamente a un tipo de puntero. Como tal, en tus working_on_pointers , aExpect y pExpect tienen exactamente el mismo tipo. A pesar de la notación de estilo de matriz, ha definido aExpect como que tiene el tipo ‘puntero a int’. Como los dos son iguales, se espera que actúen igual.

Eche un vistazo a esta respuesta que publiqué en relación con las diferencias entre punteros y matrices aquí en SO .

Espero que esto ayude.

bien, puedo estar equivocado pero las matrices y los punteros se pueden utilizar alternativamente.

 int * ptr = (int *)malloc(2* sizeof(int)); ptr[0]=1; ptr[1]=2; printf ("%d\n", ptr[0]); printf ("%d\n", ptr[1]); 

Aquí declaré un puntero y ahora lo estoy tratando como una matriz.

además:

Como consecuencia de esta definición, no hay una diferencia aparente en el comportamiento del operador “subíndice de matriz” [], ya que se aplica a matrices y punteros. En una expresión de la forma a [i], la referencia de matriz “a” se desintegra en un puntero, siguiendo la regla anterior, y luego se subíndice como sería una variable de puntero en la expresión p [i] (aunque la memoria final Los accesos serán diferentes, como se explica en la pregunta 2.2). En cualquier caso, la expresión x [i] (donde x es una matriz o un puntero) es, por definición, idéntica a * ((x) + (i)).

referencia: http://www.lysator.liu.se/c/c-faq/c-2.html

Necesitas entender el concepto básico de los arreglos.

cuando se declara una matriz es decir

 int farr[] 

En realidad estás declarando un puntero con esta statement.

 const int * farr 

es decir; un puntero “constante” a entero. así que cuando haces farr ++ en realidad estás tratando de sumr un puntero que es constante, por lo tanto, los comstackdores te dan un error.

Si necesita comprender, intente declarar un puntero con la statement anterior y no podrá hacer la aritmética que es legal en los punteros normales.

PD: ha estado tranquilo un tiempo, he codificado en C, así que no estoy seguro de la syntax exacta. pero la línea inferior es la diferencia entre un puntero y un puntero constante.