2010-01-19 11 views
196

Estoy comenzando con punteros, y estoy un poco confundido. Sé que & significa la dirección de una variable y que * se puede usar delante de una variable de puntero para obtener el valor del objeto apuntado por el puntero. Pero las cosas funcionan de manera diferente cuando se trabaja con matrices, cadenas o cuando se llaman funciones con una copia de puntero de una variable. Es difícil ver un patrón de lógica dentro de todo esto.Punteros en C: ¿cuándo usar el signo y el asterisco?

¿Cuándo debo usar & y *?

+3

Por favor, ilustra cómo ves que las cosas a veces funcionan de manera diferente. De lo contrario, tenemos que adivinar qué es lo que te está confundiendo. –

+1

De acuerdo con Neil Butterworth. Probablemente va a obtener mucha más información obteniéndolo de primera mano de un libro, y la explicación de K & R es bastante clara. – Tom

+1

Aunque * es * un tema difícil de buscar en esto se ha discutido una y otra vez en varias formas. Los siguientes están tomados de http://stackoverflow.com/search?q=c+pointer+basic y probablemente sean relevantes (estoy seguro de que hay un duplicado, pero no lo he encontrado): http: // stackoverflow .com/questions/5727/what-are-the-barriers-to-understanding-puninters-and-what-can-be-done-to-overcome http://stackoverflow.com/questions/897366/how-do- puntero-a-punteros-trabajo-en-c http://stackoverflow.com/questions/162941/why-use-pointers http://stackoverflow.com/questions/500886/how-to-approach-pointers-in- c – dmckee

Respuesta

441

Usted tiene punteros y valores:

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

que encienda un puntero en un valor con *:

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

que encienda un valor en un puntero con &:

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

Edit: En el caso de matrices, t hey son tratados como punteros. Si se piensa en ellos como punteros, que va a utilizar * para llegar a los valores dentro de ellos como se explicó anteriormente, pero hay también otra forma, más común 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 

Así 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 
+74

+1 para una explicación más concisa y amigable para el principiante – Kena

+0

¿Cómo es que esto no funciona? 'int aX [] = {3, 4}; int * bX = &aX; ' – Pieter

+1

Las matrices son especiales y se pueden convertir a punteros de forma transparente. Esto resalta otra forma de pasar de un puntero a un valor, lo agregaré a la explicación anterior. –

1

Ok, parece que su puesto consiguió Editted ...

double foo[4]; 
double *bar_1 = &foo[0]; 

ver cómo se puede utilizar el & para obtener la dirección del comienzo de la estructura matriz? El siguiente

Foo_1(double *bar, int size){ return bar[size-1]; } 
Foo_2(double bar[], int size){ return bar[size-1]; } 

hará lo mismo.

+0

La pregunta ha sido etiquetada C no C++. –

+1

Y eliminé el cout ofensivo << – wheaties

3

En realidad, lo tienes abajo pat, no hay nada más que necesita saber :-)

me acaba de añadir 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 "se degradan" a los punteros cuando los pasa a funciones.
  • en realidad puede tener varios niveles en direccionamiento indirecto (char **p significa que p es un puntero a un puntero a char.

En cuanto a las cosas que trabajan de manera diferente, en realidad no:

  • matrices, como ya se ha mencionado, se degrada a los punteros (para el primer elemento de la matriz) Cuando se transmite a las funciones; no conservan la información de tamaño.
  • no hay cadenas en C, solo matrices de caracteres que, por convención, representan una cadena de caracteres terminados por un carácter cero (\0).
  • Cuando pasa la dirección de una variable a una función, puede des-referenciar el puntero para cambiar la variable en sí (normalmente las variables se pasan por valor (excepto para las matrices)).
3

Creo que está un poco confundido. Debes leer un buen tutorial/libro sobre punteros.

This tutorial es muy bueno para principiantes (explica claramente qué & y * son). Y sí, no olvides leer el libro Punteros en C de 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; 
} 
4

Cuando está declarando un parámetro variable puntero o función, utilice 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 se suelen tratar como punteros. Cuando declaras un parámetro de matriz en una función, puedes declarar fácilmente 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 exactamente las reglas. Puede tomar la dirección de una función sin usar &, y puede llamar a un puntero de función sin usar *.

20

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 aparece una expresión de matriz en la mayoría de contextos, el tipo de expresión se convierte implícitamente de "N-elemento matriz de T" a "puntero a T", y su valor está configurado para apuntar al primer elemento en la matriz. Las excepciones a esta regla son cuando la expresión del arreglo aparece como un operando de los operadores & o sizeof, o cuando se trata de un literal de cadena que se utiliza como un inicializador en una declaración.

Por lo tanto, cuando se 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 eso que no utiliza 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 a th e principio de la matriz str. Esto es válido para cualquier función llamada con una expresión de matriz como argumento (cualquiera de las funciones str*, *scanf y *printf, etc.).

En la práctica, es probable que nunca se llama 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]) {...} 

Tal código no es muy común; debe saber 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 a un puntero a una matriz de 11 elementos de T).

Cuando una expresión de matriz aparece como un operando al operador &, el tipo de la expresión resultante es "puntero a la matriz N-elemento de T", o T (*)[N], que es diferente de una matriz de punteros (T *[N]) y un puntero al tipo de base (T *).

Cuando se trata de funciones y punteros, la regla para recordar es: si desea cambiar el valor de un argumento y hacerlo reflejar en el código de llamada, debe pasar un puntero al objeto que desea modificar. De nuevo, las matrices lanzan un poco de llave inglesa a las obras, pero primero trataremos con 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 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 = x; } 
... 
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); 

Usted obtendrá el siguiente resultado:

 
before swap: a = 1, b = 2 
after swap: a = 1, b = 2 

Los parámetros formales x y y son objetos distintos de a y b, por lo que los cambios en x y y no se reflejan en a y b.Dado que queremos modificar los valores de a y b, debemos pasar punteros a ellos 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 su salida será

 
before swap: a = 1, b = 2 
after swap: a = 2, b = 1 

Tenga en cuenta que, en el canje función, no cambiamos los valores de x y y, pero los valores de x y yapuntan a. Escribir en *x es diferente de escribir en x; no estamos actualizando el valor en x, obtenemos una ubicación desde 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 del parámetro de entrada stream, no lo streampuntos a, por lo que cambiar stream no tiene ningún efecto sobre el valor de in; Para que esto funcione, tenemos que pasar en un puntero al puntero:

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

Una vez más, las matrices tirar un poco de una llave inglesa en las obras. Cuando pasa una expresión de matriz a una función, lo que recibe la función es un puntero. Debido a cómo se define subíndices de matriz, se puede utilizar un operador subíndice en un puntero de la misma manera que se puede utilizar 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;} 

en cuenta que los objetos de matriz no pueden ser asignados; es decir, no se puede hacer algo como

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

por lo que desea tener cuidado cuando se está tratando con punteros a las matrices; algo como

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

no funcionará.

+4

+1 durante la duración de la respuesta – Dave

8

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 o bien:

  • a) * da acceso al valor de esa variable (si el tipo de esa variable es un tipo de puntero , o sobrecargó el operador *).
  • b) * tiene el significado de que el operador se multiplican, en ese caso, tiene que ser otra variable a la izquierda de la *

Si * aparece en una variable o función declaració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 

If & aparece en una declaración de variable o función, por lo general 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 usted debe saber, que al pasar una matriz a una función, siempre se tendrá que pasar el tamaño de la matriz de esa matriz también, excepto cuando la matriz es algo así como una cstring terminada en 0 (matriz de caracteres).

+0

@akmozo s/func_takes int_ptr2/func_takes_int_ptr2/(espacio no válido) – PixnBits

8

En pocas palabras

  • & significa que el dirección de, se verá que en los marcadores de posición para las funciones para modificar la variable de parámetros como en C, las variables de los parámetros se pasan por valor, utilizando el signo significa pasar por referencia.
  • * significa la desreferenciación de de una variable de puntero, 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 de foo mediante pase por referencia, comparar con esta

 
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í está un ejemplo de uso de un dereference

 
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 el addr ess-ofy y se lo asignó a la variable de puntero p. Luego, desreferenciap conectando el * al frente del mismo para obtener el valor de p, es decir, *p.

1

Estaba revisando todas las explicaciones verbales, así que en su lugar recurrí a un video de la Universidad de Nueva Gales del Sur para rescatarlo. Aquí está la explicación simple: si tenemos una celda que tiene la dirección x y el valor 7, la forma indirecta de pedir la dirección del valor 7 es &7 y la forma indirecta de pedir valor en la dirección x es *x .So (cell: x , value: 7) == (cell: &7 , value: *x) manera .Otro a mirar en él: John sienta a 7th seat .El *7th seat apuntará a John y &John dará address/ubicación del 7th seat. Esta simple explicación me ayudó y espero que ayude a otros también.Aquí está el enlace para el vídeo excelente: click here.

Aquí está 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(); 
} 

Add-on: Siempre inicializar puntero antes no usar them.If, el puntero que apunte a nada, lo cual podría ocasionar la falla del programa porque el sistema operativo le impedirá acceder a la memoria que sabe que no posee. Pero simplemente poniendo p = &x;, estamos asignando al puntero una ubicación específica.

Cuestiones relacionadas