How does the scanf function work in C?

2019-01-15 15:05发布

问题:

Why do you require ampersand (&) in the scanf function. What will the output or type of error (compile or runtime) be in the following C code?

#include <stdio.h>

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

回答1:

The & in C is an operator that returns the address of the operand. Think of it this way, if you would simply give scanf the variable a without the &, it will be passed to it by-value, which means scanf will not be able to set its value for you to see. Passing it by-reference (using & actually passes a pointer to a) allows scanf to set it so that the calling functions will see the change too.

Regarding the specific error, you can't really tell. The behavior is undefined. Sometimes, it might silently continue to run, without you knowing scanf changed some value somewhere in your program. Sometimes it will cause the program to crash immediately, like in this case:

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

Compiling it shows this:

$ 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’

And executing shows a segmentation fault:

$ ./test 
enter integer: 2
Segmentation fault


回答2:

In C, all function arguments are passed by value; any changes to the function's formal parameter are not reflected in the actual parameter. For example:

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;
}

The output of the program will be

x before foo = 0
x after foo = 0

because bar receives the value of x (0), not a reference to x itself. Changing bar has no effect on x.

In C, the way around this is to pass a pointer to a 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;
}

Now the output of the program is

x before foo = 0
x after foo = 1

This time, the formal parameter bar is not an int, but a pointer to int, and it receives the address of x (given by the expression &x in the call to foo), not the value contained in x. The expression *bar means "get the value in the location bar points to", so *bar = *bar + 1 corresponds to x = x + 1.

Since scanf() needs to write to its arguments, it expects those arguments to typed as pointers. The "%d" conversion specifier expects the corresponding argument to be a pointer to int (int *), the "%u" conversion specifier expects a pointer to unsigned int (unsigned *), "%s" expects a pointer to char (char *), "%f" expects a pointer to float (float *), etc. In your example, since a is typed int, you need to use the expression &a to get a pointer.

Note that if a were already a pointer type, you would not need to use the & operator in the call to 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
  ...
}

Note also that when passing an array to a function (such as when using the "%s" conversion specifier to read a string), you don't need to use the & operator; the array expression will implicitly be converted to a pointer type:

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


回答3:

If you're asking a question like this, I would recommend just learning for now "it just does".

You will learn that you need an ampersand because scanf takes one or more pointer arguments. If a is an int variable, it is not a pointer. &a ("the address of a") is a pointer, so it will work with scanf.



回答4:

This is because in C, functions parameters are passed by value. In order for the scanf() function to modify the 'a' variable in your main() function, the address of 'a' shall be given to scanf(), hence the usage of the ampersand (address of).



回答5:

Because scanf requires a pointer to the variable (i.e. a reference) that the value will go into.



回答6:

You don't always need to use an & with scanf. What you need to do is to pass pointers. If you're new to C, you should spend some time reading the comp.lang.c FAQ:

http://c-faq.com/

Specifically:

  • Why doesn't the call scanf("%d", i) work?
  • Why does the call scanf("%s", s) work?


回答7:

The '&' in scanf is only required to get the address of a variable. You can use scanf without '&' by using pointers:

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

In general, using '&' is often easier than creating pointer to avoid using the '&'.



标签: c scanf