2010-10-22 49 views
9

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 ella. Cualquier cambio realizado en los argumentos formales no afecta los argumentos reales.Pasar matriz completa a una función

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

+2

Creo que mi respuesta (detallada) a esta otra pregunta http://stackoverflow.com/questions/3613302/passing-array-of-struc tures-to-function-c/3613350 # 3613350 también cubre este. Básicamente, esa es una diferencia entre la matriz y el problema de los indicadores. – kriss

+1

¿No puedes usar const, si no quieres modificar el contenido de la matriz? – Nyan

Respuesta

16

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 realmente 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 la pila principal. Cuando desreferencia ese puntero con ptr[1], está siguiendo el puntero a la memoria principal y modificando 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 nada a lo que apunta.

Si desea hacerTarea para obtener su propia copia de la matriz, o bien envolver la matriz en una estructura como otros han sugerido, o utilizar memcpy para copiar manualmente la profundidad de la matriz de la siguiente manera:

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

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

+0

El segundo fragmento de código, ¿es válido C o simplemente pseudo C? – Nyan

+0

Ok, ¿Qué compilador estás usando? Sólo curioso. – Nyan

+0

gcc versión 4.1.2 – AlcubierreDrive

0

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

+4

Una matriz en C no es un puntero, a menudo * se degrada * a un puntero. –

+0

@Matteo, @paxdiablo Reparado. – Jonathan

8

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

0

Porque cuando pasa una matriz completa para funcionar, pasa una apunta a esa matriz, lo que significa que le da a la función un lugar en la memoria donde se encuentra esta matriz. Entonces, cuando cambia la matriz en la función, también está cambiando la matriz original.

5

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

Si realmente desea pasar una matriz, lo envuelve 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)); 
} 
2

"el paso por referencia" es una cortina de humo en C. Todos los argumentos a una función se "pasan por valor" solamente . En el caso de las matrices, pasa la dirección del primer elemento en forma de un puntero. A continuación, puede utilizar este puntero para hacer referencia a la ubicación de memoria deseada & leer o escribir valores.

2

Desde el online C standard:

6.3.2.1 Lvalues, matrices y designadores de función
...
3, excepto cuando es el operando de la sizeof operador o el unario y operador, o es una cadena literal utilizado 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 matriz y no es un valor l. Si el objeto de matriz tiene una clase de almacenamiento de registro, el comportamiento no está definido.

asumir el código siguiente fragmento:

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

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

Por lo tanto, lo que foo recibe es un puntero a int, no una matriz. La desreferenciación o la subscripción de 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 las circunstancias (incluida la creación de subíndices), las expresiones del array se convertirán a tipos de punteros.

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

3

Todavía no he visto ninguna respuesta pero cubro toda la pregunta todavía. Por lo que veo, parece que la pregunta se refiere a algo como esto:

Dado el siguiente código:

int a[5]; 

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

Por qué puede foo manipular los valores originales, mientras que bar recibe sólo una copia del valor que se pasa en ?

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

Así

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

es diferente que:

int* a; 
bar(a); 

Si desea pasar de una referencia a un elemento específico en una matriz, es necesario utilizar el & operador:

bar(&a[5]); 
Cuestiones relacionadas