¿Por qué usar y pasar valor para la función con *?

Quería preguntarle al autor, caf, desde Entendiendo funciones y punteros en C

Me di cuenta de que no puedo hacer la pregunta en esa misma página.

Todavía estoy confundido con el uso de & para pasar el valor del puntero a una función. Siempre pensé y q solo está pasando la dirección de q, ¿cómo se va a traducir el valor de q en int sqp (int * x)?

No hay “traducción”.

Tu funcion

 int sqp(int *x); 

toma un argumento, x , cuyo tipo es int * , es decir, “puntero a entero”.

Por lo tanto, para llamarlo debe pasarle un puntero a un entero, es decir, a la dirección de un entero.

El operador & prefijo se usa para calcular la dirección de su argumento, por lo que puede hacer:

 int foo = 4711; sqp(&foo); 

para llamar a la función sqp() con la dirección de la variable foo .

Utilizando:

 sqp(&q); 

pasa la dirección de q como un argumento en la función int sqp(int *x) .

A partir de ahora, dentro de esta función, utilizando x obtendrá esta dirección.

Usando *x obtienes el valor contenido en esta dirección en la memoria.

Así es como podemos “simular” pass by reference en C , pasando por valor la dirección de la variable como un argumento en la función.

Como usted dijo &q pasa la dirección de memoria de la variable q para que funcione, entonces lo que enviamos a la función es solo la dirección de q . La función no necesita traducir ningún valor porque accede directamente al valor original, ya que tiene la dirección almacenada en el puntero x y cada vez que haces algo como *x=7; con la * dereferencia de una variable, eso significa que no está modificando la variable x , en cambio modifica lo que x apunta.

En el caso de llamada por referencia, se pasa una dirección para que se puedan hacer cambios al referirse a la dirección (es decir, referencia) y si está pasando la dirección en el argumento, debería tener algún mecanismo para apuntar a esa dirección. Y Pointer es algo que apunta a la dirección para llamar si ha pasado la dirección, tiene que usar el puntero en la definición para señalarla. ejemplo.

 calling(&a); //passing address void calling(int *b) //Pointing to address of 'a' via pointer 'b' { //some code } 

Um, ¿sabes punteros? Asumiré que lo haces ^ o ^

Hay dos formas de pasar el argumento. Pass-By-Value y Pass-By-Reference .

Tal vez usualmente usas el paso por valor .

 #include  void foo(int i) { printf("[foo] `i` was %d\n", i); i++; printf("[foo] Now `i` is %d\n", i); } int main() { int i = 0; printf("[main] `i` was %d\n", i); foo(i); printf("[main] Now `i` is %d\n", i); } 

La salida es: ( ejemplo en vivo )

 [main] `i` was 0 [foo] `i` was 0 [foo] Now `i` is 1 [main] Now `i` is 0 

Sí, la i de main() no se cambia! ¿Por qué?

Porque i se pasa por valor . Cuando se ejecuta foo(i) , el valor de i se copia y foo usa la copia, no el i original. Así que no se puede cambiar.


Sin embargo, ha visto la función que cambia el argumento, por ejemplo, scanf .

 int main() { int i = 0; scanf("%d", &i); /* `i` is changed!! */ } 

¿Cómo puede ser cambiado? Porque scanf utiliza pass-by-ref . Mira este ejemplo.

 #include  void foo(int *pi) { printf("[foo] `i` was %d\n", *pi); (*pi)++; /* please be careful ^o^ */ printf("[foo] Now `i` is %d\n", *pi); } int main() { int i = 0; printf("[main] `i` was %d\n", i); foo(&i); printf("[main] Now `i` is %d\n", i); } 

La salida es: ( ejemplo en vivo )

 [main] `i` was 0 [foo] `i` was 0 [foo] Now `i` is 1 [main] Now `i` is 1 

¿Como es posible? Porque pasamos el puntero de i , no la copia de i . foo tiene el puntero de i , por lo que puede acceder a la i , que tiene main . Lo llamamos paso por referencia .

Espero que te pueda ayudar!

Acortando un poco el ejemplo de la respuesta en la pregunta vinculada:

 void sqp(int *x) { *x = 10; } void foo() { int value = 42; sqp(&value); } 

Entonces, sqp es una función que quiere devolver datos a través de su parámetro, lo que significa que tiene que saber dónde escribir. Esta información es un puntero – la dirección de memoria a usar. Cuando se pasa el lenguaje C, no se pasa automáticamente el puntero sino una statement como sqp(value); (si el comstackdor no lo prohíbe debido a tipos incompatibles) pasaría el valor, en este caso 42. La función sqp luego vería el 42 y lo interpretaría como una dirección e intentaría escribir en la ubicación 42 de la memoria, que probablemente no es El lugar donde deben ir los datos.

Ahora la pregunta es por qué el comstackdor no puede hacer la deducción por sí mismo. La función requiere un puntero a int y nosotros proporcionamos un int para que pueda deducirse automáticamente.

Veo al menos dos razones para no hacer las deducciones.

  • Hace que el código de llamada sea más claro: el & le dice al lector que estamos pasando la dirección y que el valor podría cambiar
  • La deducción no es posible en todos los casos. es decir, con una función que espera un void * puede que el comstackdor no aclare si se necesita un nivel adicional cuando ya no se proporciona un puntero.

Sí, &q es la dirección de q . El valor de q no está “traducido”; es solo que si tiene la dirección de q , una de las cosas que puede hacer con esa dirección es acceder al objeto q sí.

Así que echemos un vistazo a la definición de la función sqp nuevo:

 int sqp( int *x ) { ... } 

Las declaraciones en C se basan en los tipos de expresiones , no en objetos; si tiene un puntero a un entero llamado x y desea acceder al valor entero al que se apunta, no hace referencia a x con el operador unario * , de esta manera:

 int y = *x; 

El tipo de expresión *x es int , por lo que la statement de la variable x se escribe como

 int *x; 

Cuando escuchas a alguien usar la frase “statement que imita el uso”, esto es lo que significan.

Cuando llamamos a la función como

 y = sqp( &q ); 

la expresión &q produce la dirección de q , y el tipo de expresión es int * . El parámetro x en sqp recibe ese valor de dirección.

Por lo tanto, la expresión *x en sqp es equivalente a la expresión q en la función de llamada; ambas expresiones se refieren al mismo objeto en la memoria y ambas evalúan al mismo valor. Del mismo modo, la expresión x en sqp es equivalente a la expresión &q en la función de llamada; Ambos evaluarán a la dirección de q .