2010-08-05 12 views
6

En el programa C a continuación, no entiendo por qué buf [0] = 'A' después de llamar a foo. ¿No está haciendo foo by-value?C Programación - Pase por referencia

#include <stdio.h> 
#include <stdlib.h> 

    void foo(char buf[]) 
    { 
     buf[0] = 'A'; 
    } 

    int main(int argc, char *argv[]) 
    { 
     char buf[10]; 

     buf[0] = 'B'; 
     printf("before foo | buf[0] = %c\n", buf[0]); 
     foo(buf); 
     printf("after foo | buf[0] = %c\n", buf[0]); 

     system("PAUSE"); 
     return 0; 
     } 

de salida:

before foo | buf[0] = 'B' 
after foo | buf[0] = 'A' 

Respuesta

12
void foo(char buf[]) 

es lo mismo que

void foo(char* buf) 

Cuando se llame, foo(buf), pasa un puntero de valor, por lo que se hace una copia del puntero.

La copia del puntero apunta al mismo objeto que el puntero original (o, en este caso, al elemento inicial de la matriz).

C no tiene una semántica de paso por referencia en el sentido de que C++ tiene semántica de paso por referencia. Todo en C pasa por valor. Los punteros se usan para pasar la semántica de referencia.

+0

Gracias a todos, especialmente a James, por la respuesta. ¿Por qué alguien usaría la llamada por valor si no cambia el valor de la entrada? –

+0

Porque puede necesitar un valor de algo pero no necesita cambiarlo. – Javier

+2

@Kevin: Porque la función solo puede necesitar el valor. Las funciones sin efectos secundarios son más fáciles de razonar (no es que llegue muy lejos usando C como un lenguaje de programación funcional), y pasar por el valor elimina los posibles efectos secundarios. –

1

* auto char buf [] significa en realidad char ** por lo que estás pasando por puntero/referencia. Eso le da a usted que buf es un puntero, tanto en el principal() como en el foo() función.

1

Porque está pasando un puntero a buf (por valor). Por lo tanto, se cambia el contenido apuntado por buf.

4

una matriz es simplemente una forma elegante de utilizar un puntero. Cuando pasa buf a la función, está pasando un puntero por valor, pero cuando desreferencia el puntero, todavía está haciendo referencia a la cadena a la que apunta.

0

para pasar eso por valor, la función necesitaría saber el tamaño del argumento. En este caso, solo está pasando un puntero.

1

Con punteros es diferente; está pasando por valor, pero lo que está pasando es el valor del puntero, que no es lo mismo que el valor de la matriz.

Por lo tanto, el valor del puntero no cambia, pero está modificando lo que apunta.

2

matriz como parámetro de la función es equivalente a un puntero, así que la declaración

void foo(char buf[]); 

es la misma que

void foo(char* buf); 

El argumento de matriz es entonces decayó al puntero a su primer elemento .

0

Usted está pasando por referencia aquí. En este ejemplo, puede resolver el problema pasando un solo carácter en el índice de la matriz deseada.

Si desea conservar el contenido de la matriz original, puede copiar la cadena al almacenamiento temporal en la función.

editar: ¿Qué pasaría si envuelve su matriz de caracteres en una estructura y pasa la estructura?Creo que eso también podría funcionar, aunque no sé qué tipo de sobrecarga podría crear a nivel de compilador.

0

tenga en cuenta una cosa,

declaración

void foo(char buf[]) 

dice que va a utilizar [] notación. No qué elemento de matriz usará.

si le gustaría señalar que, usted desea conseguir algún valor específico, entonces usted debe declarar esta función como

void foo(char buf[X]); //where X would be a constant. 

Por supuesto que no es posible, porque sería inútil (función para la operación en el n-ésimo elemento de la matriz?). No es necesario que escriba información sobre qué elemento de la matriz desea obtener. Todo lo que necesita es simple declaración:

voi foo(char value); 

así que ...

void foo(char buf[]) 

es una declaración que dice lo que la notación que desea utilizar ([] - parte), y también contiene puntero algunos datos.

Además ... ¿qué se puede esperar ... que envió a la función foo un nombre de matriz

foo(buf); 

lo que equivale a & buf [0]. Entonces ... esto es un puntero.

0

Las matrices en C no se pasan por valor. Ni siquiera son parámetros de función legítimos. En su lugar, el compilador ve que estás tratando de pasar una matriz y degradarla a un puntero. Lo hace en silencio porque es malvado. También le gusta patear cachorros.

Utilización de matrices de parámetros de la función es una buena manera de indicar a los usuarios de la API que esto debe ser un bloque de memoria segmentada en trozos del tamaño de N bytes, pero no espere compiladores a importar si se escribe o char *foochar foo[]char foo[12] en parámetros de funciones. Ellos no lo harán.

2

Las matrices se tratan de manera diferente a otros tipos; no se puede pasar una matriz "por valor" en C.

Online C99 standard (draft n1256), sección 6.3.2.1, "Lvalues, matrices y designadores de función", párrafo 3:

excepto cuando es el operando de la operador sizeof o el operador unario &, o es un literal de cadena utilizado para inicializar una matriz, una expresión que tiene tipo '' matriz de tipo '' es convertida a una expresión con tipo '' puntero a tipo '' que apunta a el elemento inicial de el objeto de matriz y no es un valor l. Si el objeto de matriz tiene una clase de almacenamiento de registro, el comportamiento de no está definido.

En la llamada

foo(buf); 

la expresión de matriz buf no es el operando de sizeof o &, ni es una cadena literal que se utiliza para inicializar una matriz, por lo que se implícitamente Modificada ("desintegraciones ") de tipo" matriz de 10 elementos de char "a" puntero a char ", y la dirección del primer elemento se pasa a foo. Por lo tanto, cualquier cosa que haga a buf en foo() se reflejará en la matriz buf en main(). Debido a la definición de la subscripción de matriz, puede usar un operador de subíndices en un tipo de puntero para que se vea como como si estuviera trabajando con un tipo de matriz, pero no es así.

En el contexto de una declaración de parámetros de función, T a[] y T a[N] son sinónimo de T *a, pero esto es solamente caso de que eso es cierto.

1

matrices y punteros son (casi) lo mismo.

int* foo = malloc(...) 

foo[2] es lo mismo que *(foo+2*sizeof(int))

anécdota: usted escribió

int main(int argc, char *argv[]) 

también es legal (compilará y funcionan de la misma) para escribir

int main(int argc, char **argv) 

y también

int main(int argc, char argv[][]) 

son efectivamente lo mismo. es un poco más complicado que eso, porque una matriz sabe cuántos elementos tiene, y un puntero no. pero se usan igual.

Cuestiones relacionadas