que - punteros como parametros de funciones en c
Punteros en C: ¿cuándo usar el símbolo y el asterisco? (9)
Creo que estás un poco confundido. Deberías leer un buen tutorial / libro sobre punteros.
This tutorial es muy bueno para empezar (explica claramente qué y &
son *
). Y sí, no te olvides de leer el libro Punteros en C por Kenneth Reek.
La diferencia entre &
y *
es muy clara.
Ejemplo:
#include <stdio.h>
int main(){
int x, *p;
p = &x; /* initialise pointer(take the address of x) */
*p = 0; /* set x to zero */
printf("x is %d/n", x);
printf("*p is %d/n", *p);
*p += 1; /* increment what p points to i.e x */
printf("x is %d/n", x);
(*p)++; /* increment what p points to i.e x */
printf("x is %d/n", x);
return 0;
}
Estoy empezando con punteros, y estoy un poco confundido. Sé &
significa la dirección de una variable y que *
se puede usar delante de una variable de puntero para obtener el valor del objeto al que apunta el puntero. Pero las cosas funcionan de manera diferente cuando trabaja con matrices, cadenas o cuando llama a funciones con una copia de puntero de una variable. Es difícil ver un patrón de lógica dentro de todo esto.
¿Cuándo debo usar &
y *
?
Cuando esté declarando una variable de puntero o un parámetro de función, use el *:
int *x = NULL;
int *y = malloc(sizeof(int)), *z = NULL;
int* f(int *x) {
...
}
NB: cada variable declarada necesita su propio *.
Cuando desee tomar la dirección de un valor, use &. Cuando desee leer o escribir el valor en un puntero, use *.
int a;
int *b;
b = f(&a);
a = *b;
a = *f(&a);
Las matrices son generalmente tratadas como punteros. Cuando declara un parámetro de matriz en una función, puede declarar con la misma facilidad que es un puntero (significa lo mismo). Cuando pasa una matriz a una función, en realidad está pasando un puntero al primer elemento.
Los punteros de función son las únicas cosas que no siguen las reglas. Puede tomar la dirección de una función sin usar &, y puede llamar a un puntero de función sin usar *.
De hecho, lo tienes muy claro, no hay nada más que debas saber :-)
Simplemente añadiría los siguientes bits:
- Las dos operaciones son extremos opuestos del espectro.
&
toma una variable y le da la dirección,*
toma una dirección y le da la variable (o contenidos). - las matrices "degradan" a los punteros cuando se pasan a las funciones.
- en realidad, puede tener varios niveles en direccionamiento indirecto (
char **p
significa quep
es un puntero a un puntero a unchar
.
En cuanto a las cosas que funcionan de manera diferente, no realmente:
- las matrices, como ya se mencionó, se degradan a los punteros (al primer elemento de la matriz) cuando se pasan a las funciones; no conservan información de tamaño
- no hay cadenas en C, solo matrices de caracteres que, por convención, representan una cadena de caracteres terminada por un carácter cero (
/0
). - Cuando pasa la dirección de una variable a una función, puede desviar la referencia del puntero para cambiar la variable en sí misma (normalmente las variables se pasan por valor (excepto para matrices)).
En pocas palabras
-
&
significa la dirección de , verá que en los marcadores de posición para que las funciones modifiquen la variable de parámetro como en C, las variables de parámetro se pasan por valor, utilizando los medios de signo para pasar por referencia. -
*
significa la desreferencia de una variable de puntero, lo que significa obtener el valor de esa variable de puntero.
int foo(int *x){ *x++; } int main(int argc, char **argv){ int y = 5; foo(&y); // Now y is incremented and in scope here printf("value of y = %d/n", y); // output is 6 /* ... */ }
El ejemplo anterior ilustra cómo llamar a una función foo
usando paso por referencia, compare con esto
int foo(int x){ x++; } int main(int argc, char **argv){ int y = 5; foo(y); // Now y is still 5 printf("value of y = %d/n", y); // output is 5 /* ... */ }
Aquí hay una ilustración del uso de una desreferencia
int main(int argc, char **argv){ int y = 5; int *p = NULL; p = &y; printf("value of *p = %d/n", *p); // output is 5 }
Lo anterior ilustra cómo obtuvimos la dirección de y
y la asignamos a la variable de puntero p
. Luego, desreferimos p
al adjuntar el *
al frente para obtener el valor de p
, es decir, *p
.
Estaba mirando a través de todas las explicaciones verbales, por lo que recurrí a un video de la Universidad de Nueva Gales del Sur para su rescate. Aquí está la explicación simple: si tenemos una celda que tiene la dirección x
y el valor 7
, la forma indirecta de solicitar la dirección de el valor 7
es &7
y la forma indirecta de pedir valor en la dirección x
es *x
. Por lo tanto (cell: x , value: 7) == (cell: &7 , value: *x)
.Otra forma de verlo: John
se sienta en el 7th seat
. El *7th seat
apuntará a John
y &John
dará la address
/ ubicación del 7th seat
. Esta simple explicación me ayudó y espero que también ayude a otros. Aquí está el enlace para el excelente video: haga clic aquí.
Aquí hay otro ejemplo:
#include <stdio.h>
int main()
{
int x; /* A normal integer*/
int *p; /* A pointer to an integer ("*p" is an integer, so p
must be a pointer to an integer) */
p = &x; /* Read it, "assign the address of x to p" */
scanf( "%d", &x ); /* Put a value in x, we could also use p here */
printf( "%d/n", *p ); /* Note the use of the * to get the value */
getchar();
}
Complemento: siempre inicie el puntero antes de usarlos. De lo contrario, el puntero apuntará a cualquier cosa, lo que podría ocasionar un bloqueo del programa porque el sistema operativo le impedirá acceder a la memoria que sabe que no posee. p = &x;
, estamos asignando al puntero una ubicación específica.
Hay un patrón cuando se trata de matrices y funciones; Es un poco difícil de ver al principio.
Cuando se trata de matrices, es útil recordar lo siguiente: cuando una expresión de matriz aparece en la mayoría de los contextos, el tipo de expresión se convierte implícitamente de "matriz de elemento N de T" a "puntero a T", y su valor se establece para apuntar al primer elemento de la matriz. Las excepciones a esta regla son cuando la expresión de matriz aparece como un operando de los operadores &
o sizeof
, o cuando se trata de un literal de cadena que se utiliza como inicializador en una declaración.
Por lo tanto, cuando llama a una función con una expresión de matriz como argumento, la función recibirá un puntero, no una matriz:
int arr[10];
...
foo(arr);
...
void foo(int *arr) { ... }
Es por esto que no usa el operador &
para los argumentos correspondientes a "% s" en scanf()
:
char str[STRING_LENGTH];
...
scanf("%s", str);
Debido a la conversión implícita, scanf()
recibe un valor char *
que apunta al comienzo de la matriz str
. Esto es válido para cualquier función llamada con una expresión de matriz como un argumento (casi cualquiera de las funciones str*
, *scanf
y *printf
, etc.).
En la práctica, probablemente nunca llamará a una función con una expresión de matriz utilizando el operador &
, como en:
int arr[N];
...
foo(&arr);
void foo(int (*p)[N]) {...}
Tal código no es muy común; debe conocer el tamaño de la matriz en la declaración de función, y la función solo funciona con punteros a matrices de tamaños específicos (un puntero a una matriz de 10 elementos de T es un tipo diferente que un puntero a una matriz de 11 elementos) de T).
Cuando una expresión de matriz aparece como un operando para el operador &
, el tipo de la expresión resultante es "puntero a la matriz de elementos N de T", o T (*)[N]
, que es diferente de una matriz de punteros ( T *[N]
) y un puntero al tipo base ( T *
).
Cuando se trata de funciones y punteros, la regla a recordar es: si desea cambiar el valor de un argumento y reflejarlo en el código de llamada, debe pasar un puntero a lo que desea modificar. Nuevamente, las matrices lanzan un poco de llave inglesa a las obras, pero primero trataremos los casos normales.
Recuerde que C pasa todos los argumentos de función por valor; el parámetro formal recibe una copia del valor en el parámetro real, y cualquier cambio en el parámetro formal no se refleja en el parámetro real. El ejemplo común es una función de intercambio:
void swap(int x, int y) { int tmp = x; x = y; y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d/n", a, b);
swap(a, b);
printf("after swap: a = %d, b = %d/n", a, b);
Obtendrás la siguiente salida:
before swap: a = 1, b = 2 after swap: a = 1, b = 2
Los parámetros formales x
e y
son objetos distintos de a
y b
, por lo que los cambios en x
e y
no se reflejan en a
y b
. Como queremos modificar los valores de a
y b
, debemos pasarles los punteros a la función de intercambio:
void swap(int *x, int *y) {int tmp = *x; *x = *y; *y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d/n", a, b);
swap(&a, &b);
printf("after swap: a = %d, b = %d/n", a, b);
Ahora tu salida será
before swap: a = 1, b = 2 after swap: a = 2, b = 1
Tenga en cuenta que, en la función de intercambio, no cambiamos los valores de x
e y
, sino los valores a los que x
e y
apuntan . Escribir en *x
es diferente de escribir en x
; no estamos actualizando el valor en x
, obtenemos una ubicación de x
y actualizamos el valor en esa ubicación.
Esto es igualmente cierto si queremos modificar un valor de puntero; si escribimos
int myFopen(FILE *stream) {stream = fopen("myfile.dat", "r"); }
...
FILE *in;
myFopen(in);
entonces estamos modificando el valor de la stream
parámetros de entrada, no a qué puntos de la stream
, por lo que cambiar la stream
no tiene efecto en el valor de in
; para que esto funcione, debemos pasar un puntero al puntero:
int myFopen(FILE **stream) {*stream = fopen("myFile.dat", "r"); }
...
FILE *in;
myFopen(&in);
Una vez más, las matrices lanzan un poco de una llave inglesa en las obras. Cuando pasa una expresión de matriz a una función, lo que la función recibe es un puntero. Debido a cómo se definen los subíndices de matriz, puede usar un operador de subíndice en un puntero de la misma manera que puede usarlo en una matriz:
int arr[N];
init(arr, N);
...
void init(int *arr, int N) {size_t i; for (i = 0; i < N; i++) arr[i] = i*i;}
Tenga en cuenta que los objetos de matriz no pueden ser asignados; es decir, no puedes hacer algo como
int a[10], b[10];
...
a = b;
por lo que debe tener cuidado cuando se trata de punteros a matrices; algo como
void (int (*foo)[N])
{
...
*foo = ...;
}
no funcionará
Ok, parece que tu post se editó ...
double foo[4];
double *bar_1 = &foo[0];
¿Ves cómo puedes usar el &
para obtener la dirección del comienzo de la estructura de matriz? El seguimiento
Foo_1(double *bar, int size){ return bar[size-1]; }
Foo_2(double bar[], int size){ return bar[size-1]; }
Hará lo mismo.
Sí, eso puede ser bastante complicado ya que el *
se usa para muchos propósitos diferentes en C / C ++.
Si *
aparece delante de una variable / función ya declarada, significa que:
- a)
*
da acceso al valor de esa variable (si el tipo de esa variable es un tipo de puntero, o sobrecarga al operador*
). - b)
*
tiene el significado del operador multiplicar, en ese caso, tiene que haber otra variable a la izquierda de la*
Si *
aparece en una variable o declaración de función, significa que esa variable es un puntero:
int int_value = 1;
int * int_ptr; //can point to another int variable
int int_array1[10]; //can contain up to 10 int values, basically int_array1 is an pointer aswell which points to the first int of the array
//int int_array2[]; //illegal, without initializer list..
int int_array3[] = {1,2,3,4,5}; // these two
int int_array4[5] = {1,2,3,4,5}; // are indentical
void func_takes_int_ptr1(int *int_ptr){} // these two are indentical
void func_takes int_ptr2(int int_ptr[]){}// and legal
Si &
aparece en una variable o declaración de función, generalmente significa que esa variable es una referencia a una variable de ese tipo.
Si aparece &
delante de una variable ya declarada, devuelve la dirección de esa variable
Además, debe saber que al pasar una matriz a una función, siempre tendrá que pasar también el tamaño de la matriz de esa matriz, excepto cuando la matriz es algo así como una cadena de caracteres terminada en 0 (matriz de caracteres).
Tienes punteros y valores:
int* p; // variable p is pointer to integer type
int i; // integer value
Convierte un puntero en un valor con *
:
int i2 = *p; // integer i2 is assigned with integer value that pointer p is pointing to
Convierte un valor en un puntero con &
:
int* p2 = &i; // pointer p2 will point to the address of integer i
Edición: en el caso de matrices, se tratan de manera muy similar a punteros. Si piensa en ellos como punteros, usará *
para obtener los valores dentro de ellos como se explicó anteriormente, pero también hay otra forma más común de usar el operador []
:
int a[2]; // array of integers
int i = *a; // the value of the first element of a
int i2 = a[0]; // another way to get the first element
Para obtener el segundo elemento:
int a[2]; // array
int i = *(a + 1); // the value of the second element
int i2 = a[1]; // the value of the second element
Entonces el operador de indexación []
es una forma especial del operador *
, y funciona así:
a[i] == *(a + i); // these two statements are the same thing