Consejos en C: ¿cuándo utilizar el signo y el asterisco?

Resuelto Pieter asked hace 14 años • 10 respuestas

Recién estoy comenzando con los consejos y estoy un poco confundido. Sé &significa la dirección de una variable y 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 trabajas con matrices, cadenas o cuando llamas 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 *?

Pieter avatar Jan 19 '10 22:01 Pieter
Aceptado

Tienes sugerencias y valores:

int* p; // variable p is pointer to integer type
int i; // integer value

Conviertes un puntero en un valor con *:

int i2 = *p; // integer i2 is assigned with integer value that pointer p is pointing to

Conviertes un valor en un puntero con &:

int* p2 = &i; // pointer p2 will point to the integer i

Editar: en el caso de las matrices, se tratan de forma muy parecida a los punteros. Si piensa en ellos como punteros, los utilizará *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 de *operador y funciona así:

a[i] == *(a + i);  // these two statements are the same thing
Dan Olson avatar Jan 19 '2010 15:01 Dan Olson

Existe 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 aparece una expresión de matriz en la mayoría de los contextos, el tipo de expresión se convierte implícitamente de "matriz de N elementos de T" a "puntero a T", y se establece su valor. 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 es una cadena literal que se utiliza como inicializador en una declaración.

Por lo tanto, cuando llamas 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 eso 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 char *valor que apunta al comienzo de la strmatriz. Esto es válido para cualquier función llamada con una expresión de matriz como argumento (casi cualquiera de las str*funciones, *scanffunciones *printf, etc.).

En la práctica, probablemente nunca llames a una función con una expresión de matriz usando el &operador, como en:

int arr[N];
...
foo(&arr);

void foo(int (*p)[N]) {...}

Este código no es muy común; debe conocer el tamaño de la matriz en la declaración de la 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 de un tipo diferente a 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 expresión resultante es "puntero a una matriz de N elementos 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. Una vez más, las matrices suponen un pequeño problema, pero primero nos ocuparemos de los casos normales.

Recuerde que C pasa todos los argumentos de la función por valor; el parámetro formal recibe una copia del valor del 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á el siguiente resultado:

antes del intercambio: a = 1, b = 2
después del intercambio: a = 1, b = 2

Los parámetros formales xy yson objetos distintos de ay b, por lo que los cambios en xy yno se reflejan en ay b. Como queremos modificar los valores de ay b, debemos pasarles 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á

antes del intercambio: a = 1, b = 2
después del intercambio: a = 2, b = 1

Tenga en cuenta que, en la función de intercambio, no cambiamos los valores de xy y, sino los valores de what xy y apuntan a . Escribir a *xes diferente a escribir a x; No estamos actualizando el valor en xsí mismo, obtenemos una ubicación xy actualizamos el valor en esa ubicación.

Esto es igualmente cierto si queremos modificar el valor de un puntero; si escribimos

int myFopen(FILE *stream) {stream = fopen("myfile.dat", "r"); }
...
FILE *in;
myFopen(in);

entonces estamos modificando el valor del parámetro de entrada stream, no lo que stream apunta , por lo que cambiar streamno tiene ningún 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 suponen un pequeño obstáculo para el proceso. Cuando pasas una expresión de matriz a una función, lo que recibe la función es un puntero. Debido a cómo se define el subíndice de una 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 es posible que los objetos de matriz no se puedan asignar; es decir, no puedes hacer algo como

int a[10], b[10];
...
a = b;

por lo que debes tener cuidado cuando trabajes con punteros a matrices; algo como

void (int (*foo)[N])
{
  ...
  *foo = ...;
}

no funcionará.

John Bode avatar Jan 19 '2010 15:01 John Bode

En pocas palabras

  • &significa la dirección de , verá que en los marcadores de posición para funciones para modificar la variable de parámetro como en C, las variables de parámetro se pasan por valor, usando el símbolo comercial 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 foousando paso por referencia, compárelo 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
   /* ... */
}

A continuación se muestra 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 eliminamos la referencia p adjuntando el *al frente para obtener el valor de p, es decir *p.

t0mm13b avatar Jan 19 '2010 16:01 t0mm13b

Sí, eso puede ser bastante complicado ya que 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 puntero o está sobrecargado el *operador).
  • b) *tiene el significado del operador multiplicar, en ese caso, tiene que haber otra variable a la izquierda del*

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 as well 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 identical

void func_takes_int_ptr1(int *int_ptr){} // these two are identical
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 sea algo así como una cadena c terminada en 0 (matriz de caracteres).

smerlin avatar Jan 19 '2010 15:01 smerlin