Except when it is the operand of the sizeof
or unary &
operator, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T
" will be converted ("decay") to an expression of type "pointer to T
", and the value of the expression will be the address of the first element in the array.
When you write
scanf("%s", books[1].author);
the expression books[i].author
has type "33-element array of char
". By the rule above, it will be converted to an expression of type "pointer to char
" (char *
) and the value of the expression will be the address of the first element of the array.
When you write
scanf("%s", &books[1].name);
the expression books[1].name
is an operand of the unary &
operator, so the conversion doesn't happen; instead, the type of the expression &books[1].name
has type "pointer to 15-element array of char
" (char (*)[15]
), and its value is the address of the array.
In C, the address of the array and the address of the first element of the array are the same, so both expressions result in the same value; however, the types of the two expressions are different, and type always matters. scanf
expects the argument corresponding to the %s
conversion specifier to have type char *
; by passing an argument of type char (*)[15]
, you invoke undefined behavior, meaning the compiler isn't required to warn you about the type mismatch, nor is it required to handle the expression in any meaningful way. In this particular case, the code "works" (gives you the result you expect), but it isn't required to; it could just as easily have caused a crash, or led to corrupted data, depending on the specific implementation of scanf
.
Both calls should be written as
scanf("%s", books[1].name);
scanf("%s", books[1].author);
Edit
In answer to your comment, a picture may help. Here's what your books
array would look like:
+---+ +---+
| | | name[0]
| +---+
| | | name[1]
| +---+
| ...
| +---+
| | | name[14]
| +---+
books[0] | | author[0]
| +---+
| | | author[1]
| +---+
| ...
| +---+
| | | author[33]
| +---+
| | | year
+---+ +---+
| | | name[0] <------ books[1].name
| +---+
| | | name[1]
| +---+
| ...
| +---+
| | | name[14]
| +---+
books[1] | | author[0] <------ books[1].author
| +---+
| | | author[1]
| +---+
| ...
| +---+
| | | author[33]
| +---+
| | | year
+---+ +---+
Each element of the books
array contains two arrays plus an integer. books[1].name
evaluates to the address of the first element of the name
array within books[1]
; similarly, the expression books[1].author
evaluates to the address of the first element of the author
array within books[1]
.