1
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>

struct BOOK{
    char name[15];
    char author[33];
    int year;
};

struct BOOK *books;
int main(){
    int i,noBooks;
    noBooks=2;
    books=malloc(sizeof(struct BOOK)*noBooks);

    books[0].year=1986;
    strcpy(books[0].name,"MartinEden");
    strcpy(books[0].author,"JackLondon");

    //asking user to give values
    scanf("%d",&books[1].year);
    scanf("%s",&books[1].name);
    scanf("%s",books[1].author);

    printf("%d %s %s\n",books[0].year,books[0].author,books[0].name);
    printf("%d %s %s\n",books[1].year,books[1].author,books[1].name);
    getch();
    return 0;
}

I give 1988 theidiotanddostoyevski

the output is

1986 JackLondon MartinEden
1988 dostoyevski theidiot

in scanf, in books[].name i used &, in books[].author I did not use but still it did same. For year it did not work. & is useless in structure?

I mean here

scanf("%d",&books[1].year);
scanf("%s",&books[1].name);
scanf("%s",books[1].author); //no & operator

char name[15];
char author[33];

here, i can use

char *name[15];
char *author[33];

nothing changes. why i cant see the difference?

3 Answers3

1

The name member of the BOOK structure is a char array of size 15. When the name of the array is used in an expression, its value is the address of the array's initial element.

When you take an address of the name member from a struct BOOK, though, the compiler returns the base address of the struct plus the offset of the name member, which is precisely the same as the address of name's initial element. That is why both &books[1].name and books[1].name expressions evaluate to the same value.

Note: you should specify the size of the buffers into which you are going to read the strings; this will prevent potential buffer overruns:

scanf("%14s", books[1].name);
scanf("%32s", books[1].author);
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
0

This form is valid:

scanf("%s",books[1].author); 

This form is invalid:

scanf("%s", &books[1].author);

s conversion specifier expects an argument of type pointer to char in scanf function, which is true in the first statement but false in the second statement. Failing to meet this requirement makes your function call invoke undefined behavior.

In the first statement, the trailing argument (after conversion) is of type pointer to char and in the second statement, the argument is of type pointer to an array 33 of char.

ouah
  • 142,963
  • 15
  • 272
  • 331
0

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].

John Bode
  • 119,563
  • 19
  • 122
  • 198