For each conversion specifier, scanf()
expects the corresponding argument to be a pointer to the proper type: %d
expects an argument of type int *
, %f
expects an argument of type double *
, %c
and %s
both expect an argument of type char *
, etc.
The difference between %c
and %s
is that the former tells scanf()
to read a single character and store it in the location specified by the corresponding argument, while the latter tells scanf()
to read multiple characters until it sees a 0-valued character and store all those characters in the buffer starting at the location specified by the argument.
You need to use the &
operator on your arguments if they are not already of pointer type. For example:
int x;
int *px = some_valid_memory_location_such_as_&x;
char c;
char *pc = some_valid_memory_location_such_as_&c;
...
scanf("%d", &x); // x is not a pointer type, so we must use the & operator
scanf("%d", px); // px is a pointer type, so we don't need the & operator
scanf("%c", &c); // etc.
scanf("%c", pc); // etc.
Where things get confusing is reading strings of characters (using the %s
conversion specifier):
char buf[SIZE];
scanf("%s", buf); // expression 'buf' *implicitly* converted to pointer type
Why don't we need the &
operator in this case? It has to do with how C treats array expressions. When the compiler sees an expression of array type (such as buf
in the scanf()
call), it will implicitly convert the expression from type N-element array of T
to pointer to T
, and set its value to the address of the first element in the array. This value is not an lvalue -- it cannot be assigned to (so you can't write something like buf = foo
). The only exceptions to this rule are when the array expression is an operand of either the sizeof
or &
operators, or if the array expression is a string literal being used to initialize another array:
char *p = "This is a test"; // string literal implicitly converted to char *,
// string *address* written to p
char a[] = "This is a test"; // string literal not implicitly converted,
// string *contents* copied to a
In short, the expression buf
is implicitly converted from type char [SIZE]
to char *
, so we don't need to use the &
operator, and in fact the type of the expression &buf
would be pointer to SIZE-element array of char
, or (*)[SIZE]
, which is not what scanf()
expects for the %s
conversion specifier.