2010-01-14 43 views
6

¿Por qué requiere ampersand (&) en la función scanf? ¿Cuál será la salida o el tipo de error (compilación o tiempo de ejecución) en el siguiente código C?¿Cómo funciona la función scanf en C?

#include <stdio.h> 

void main() { 
    int a; 
    printf("enter integer:"); 
    scanf("%d", a); 
} 
+5

Como un aparte, 'main' devuelve' int', no 'void'. –

Respuesta

11

El & en C es un operador que devuelve la dirección del operando. Piénselo de esta manera, si simplemente le da scanf la variable a sin el &, se le pasará por valor, lo que significa que scanf no podrá establecer su valor para que usted lo vea. Pasarlo por referencia (usando & en realidad pasa un puntero a a) permite scanf configurarlo para que las funciones de llamada vean el cambio también.

En cuanto al error específico, no se puede decir realmente. El comportamiento no está definido. A veces, puede seguir ejecutándose silenciosamente, sin que usted sepa que scanf ha cambiado algún valor en algún lugar de su programa. A veces hará que el programa se bloquee inmediatamente, como en este caso:

#include <stdio.h> 
int main() 
{ 
    int a; 
    printf("enter integer: "); 
    scanf("%d",a); 
    printf("entered integer: %d\n", a); 
    return 0; 
} 

Compilarlo muestra esto:

$ gcc -o test test.c 
test.c: In function ‘main’: 
test.c:6: warning: format ‘%d’ expects type ‘int *’, but argument 2 has type ‘int’ 

y ejecución de programas de un fallo de segmentación:

$ ./test 
enter integer: 2 
Segmentation fault 
1

Debido scanf requiere un puntero a la variable (es decir, una referencia) que el valor pasará al.

2

Si Estoy haciendo una pregunta como esta, recomendaría simplemente aprender por ahora "simplemente funciona".

Aprenderá que necesita un signo comercial porque scanf toma uno o más argumentos de puntero. Si a es una variable int, no es un puntero. & a ("la dirección de a") es un puntero, por lo que funcionará con scanf.

2

Esto se debe a que en C, los parámetros de las funciones son pasados ​​por el valor. Para que la función scanf() modifique la variable 'a' en su función main(), la dirección de 'a' se debe dar a scanf(), de ahí el uso del ampersand (dirección de).

3

En C, todos los argumentos de función se pasan por valor; cualquier cambio en el parámetro formal de la función no se refleja en el parámetro real.Por ejemplo:

void foo(int bar) 
{ 
    bar = bar + 1; 
} 

int main(void) 
{ 
    int x = 0; 
    printf("x before foo = %d\n", x); 
    foo(x); 
    printf("x after foo = %d\n", x); 
    return 0; 
} 

La salida del programa será

 
x before foo = 0 
x after foo = 0 

porque bar recibe el valor de x (0), no una referencia a x sí mismo. Cambiar bar no tiene ningún efecto en x.

En C, la forma de evitar esto es para pasar un punteroa una variable:

void foo(int *bar) 
{ 
    *bar = *bar + 1; 
} 

int main(void) 
{ 
    int x = 0; 
    printf("x before foo = %d\n", x); 
    foo(&x); 
    printf("x after foo = %d\n", x); 
    return 0; 
} 

Ahora, la salida del programa es

 
x before foo = 0 
x after foo = 1 

Esta vez, el parámetro formal bar no es un int, sino un puntero a int, y recibe la dirección de x (dada por expresión &x en la llamada al foo), no el valor contenido en x. La expresión *bar significa "obtener el valor en la barra de ubicación puntos a", por lo que *bar = *bar + 1 corresponde a x = x + 1.

Dado que scanf() necesita escribir en sus argumentos, espera que esos argumentos se escriban como punteros. El especificador de conversión "% d" espera que el argumento correspondiente sea un puntero a int (int *), el especificador de conversión "% u" espera un puntero a unsigned int (unsigned *), "% s" espera un puntero a char (char *) , "% f" espera que un puntero flote (float *), etc. En su ejemplo, dado que a se escribe int, debe usar la expresión &a para obtener un puntero.

Tenga en cuenta que si a eran ya un tipo de puntero, no sería necesario utilizar el operador & en la llamada a scanf():

int main(void) 
{ 
    int a, *pa;  // declare pa as a pointer to int 
    ... 
    pa = &a;   // assign address of a to pa 
    scanf("%d", pa); // scanf() will write to a through pa 
    ... 
} 

Tenga en cuenta también que al pasar una matriz a una función (por ejemplo, cuando utilizando el especificador de conversión "% s" para leer una cadena), no necesita usar el operador &; la expresión de matriz implícitamente puede convertir en un tipo de puntero:

int main(void) 
{ 
    char name[20]; 
    ... 
    scanf("%19s", name); // name implicitly converted from "char [20]" to "char *" 
    ... 
} 
0

El '&' en scanf solamente se requiere para obtener la dirección de una variable. Usted puede scanf utilizar sin '&' mediante el uso de punteros:

int myInt; 
int * pointer_to_int; 
pointer_to_int = &myInt; 
scanf("%d", pointer_to_int); 

En general, el uso de '&' es a menudo más fácil que crear puntero a evitar el uso de la '&'.

Cuestiones relacionadas