Pasando todo el array a una función.

Cuando pasamos un elemento de una matriz a una función, se trata como una variable normal y la función llamada crea una copia del argumento real y opera en él. Cualquier cambio realizado en los argumentos formales no afecta a los argumentos reales.

Pero este no es el caso cuando pasamos toda una serie. En este caso, (llamada función) obtiene acceso a los argumentos reales y cualquier cambio realizado en los argumentos formales afecta a los argumentos reales. ¿Por qué sucede esto?

La matriz se pasa como un puntero a los elementos.

Si escribo:

void doStuff(int *ptr) { ptr[1] = 5; } int main() { int arr[] = {0, 1, 2}; doStuff(arr); printf("%d %d %d\n", arr[0], arr[1], arr[2]); } 

La salida será “0 5 2”. Eso es porque C pasa lo que sea en realidad el parámetro por valor. El parámetro es un puntero a un int. Entonces, un puntero a un int se pasa por valor. Por lo tanto, doStuff obtiene una copia de un puntero a la memoria en el marco de stack principal. Cuando hace referencia a ese puntero con ptr[1] , sigue el puntero a la memoria principal y modifica la matriz allí.

C solo puede pasar por valor, pero lo hace “superficialmente”. Si le pides que pase un int *, pasará un int *. Solo copia el valor del puntero, no los valores de lo que apunta.

Si desea que doStuff obtenga su propia copia de la matriz, envuelva la matriz en una estructura como otros lo han sugerido, o use memcpy para copiar manualmente la matriz de esta manera:

 void doStuff(int *ptr, int nElems) { int myCopyOfTheArray[nElems]; memcpy(myCopyOfTheArray, ptr, sizeof(int) * nElems); /* do stuff with the local copy */ } 

A diferencia de usar una estructura, el enfoque de memcpy funciona si nElems solo se conoce en tiempo de ejecución.

Las matrices no se pueden pasar por valor en C. Se degradan a punteros. Así que la función llamada ve un puntero a la matriz (que se pasa por referencia) y opera sobre ella. Si desea hacer una copia, debe hacerlo explícitamente o colocar su matriz dentro de una estructura (que se puede pasar por valor a las funciones).

Es caro hacer una copia de una matriz completa, en general. En los días en que se creó C por primera vez, podía agotar fácilmente los recursos de la máquina (en particular, la stack).

Si realmente quieres pasar una matriz, envuélvela en una estructura:

 struct wrap { int array[100]; }; int somefunc(struct wrap large) { ... } void anotherfunc(void) { struct wrap a; ...add data to array... printf("%d\n", somefunc(a)); } 

Aún no he visto ninguna respuesta que cubra toda la pregunta todavía. Por lo que veo, parece que la pregunta plantea algo como esto:

Dado el siguiente código:

 int a[5]; foo(a); bar(a[0]); 

¿Por qué foo puede manipular los valores originales mientras que la bar recibe solo una copia del valor que se pasa?

Esto se debe al uso de la notación de matriz: el operador [] desactiva el elemento al que hace referencia en la matriz y pasa el valor en esa ubicación.

Asi que

 int a[5]; bar(a[0]); 

es diferente a

 int* a; bar(a); 

Si desea pasar una referencia a un elemento específico en una matriz, necesita usar el operador & :

 bar(&a[5]); 

“Pasar por referencia” es una pista falsa en C. Todos los argumentos de una función son solo “pasados ​​por valor”. En el caso de matrices, se pasa la dirección del primer elemento en forma de puntero. Luego puede usar este puntero para referirse a la ubicación de memoria deseada y leer o escribir valores.

Desde el estándar C en línea :

6.3.2.1 Valores, matrices y designadores de funciones

3 Excepto cuando es el operando del operador sizeof o el operador unario & , o si se utiliza un literal de cadena para inicializar una matriz, una expresión que tiene el tipo “matriz de tipo” se convierte en una expresión con el tipo “puntero a tipo” que apunta al elemento inicial del objeto de matriz y no es un lvalue. Si el objeto de matriz tiene una clase de almacenamiento de registro, el comportamiento es indefinido.

Supongamos el siguiente fragmento de código:

 int a[10]; ... foo(a); 

En la llamada a foo , el tipo de expresión a es “matriz de 10 elementos de int “. Sin embargo, dado que la expresión no es el operando de sizeof ni de los operadores, y como no es una cadena literal que se usa para inicializar otra matriz en una statement, su tipo se convierte implícitamente (“decae”) de “10- matriz de elementos de int “a” puntero a int “, y su valor será la dirección del primer elemento de la matriz (es decir, &a[0] ).

Por lo tanto, lo que foo recibe es un puntero a int , no una matriz. Al desreferenciar o subcribir este puntero le permite cambiar los valores de la matriz.

Esta es una característica del lenguaje C; Las matrices no son objetos de primera clase. De hecho, en la mayoría de los casos (incluidos los subíndices) las expresiones de matriz se convertirán en tipos de puntero.

Sigo enfatizando la palabra expresión para distinguir entre el objeto de matriz real (que es siempre y para siempre un tipo de matriz) y cualquier referencia a ese objeto en el código, que se puede convertir en un tipo de puntero.

Porque cuando pasas una matriz completa a la función, pasas un puntero a esa matriz, lo que significa que asignas a la función un lugar en la memoria donde se ubica esta matriz. Entonces, cuando cambia la matriz en función, también está cambiando la matriz original.

Una matriz en C puede tratarse como un puntero al primer elemento de la matriz. El puntero se pasa por valor (no se puede modificar el valor pasado), pero se puede eliminar la referencia y modificar la memoria a la que apunta.