# Modularizing our code with functions

In this program we introduce modularity by separating these functionalities into well-defined functions, so that the code becomes more organized, reusable, and easier to maintain.

```c
#include <stdio.h>

#define MAX_TITLE 41
#define MAX_AUTHORS 3
#define MAX_NAME 20

struct Author {
  char first_name[MAX_NAME];
  char middle_initial;
  char last_name[MAX_NAME];
};

struct Book {
  char title[MAX_TITLE];
  struct Author authors[MAX_AUTHORS]; // Nested Author structures
  int num_authors; // Number of authors for this book
  float value;
};

void readBookDetails(struct Book *book);
void printBookDetails(struct Book book);

int main(void) {
  struct Book book1;

  readBookDetails(&book1);  // Call the function to read details

  printf("Book details:\n");
  printBookDetails(book1);  // Call the function to print details

  return 0;
}

// Function to read book details from the user
void readBookDetails(struct Book *book) {
  printf("Please enter the book title.\n");
  fgets((*book).title, MAX_TITLE, stdin);
  book->title[strcspn(book->title, "\n")] = '\0'; // Remove trailing newline

  printf("Enter the number of authors (up to %d): ", MAX_AUTHORS);
  scanf("%d", &(*book).num_authors);
  getchar(); // Consume newline character

  // Get information for each author
  for (int i = 0; i < book->num_authors && i < MAX_AUTHORS; i++) {
    printf("Enter details for author %d:\n", i + 1);
    printf("  First name: ");
    fgets(book->authors[i].first_name, MAX_NAME, stdin);
    book->authors[i].first_name[strcspn(book->authors[i].first_name, "\n")] = '\0';

    printf("  Middle initial (or hit space and enter if none): ");
    scanf("%c", &book->authors[i].middle_initial);
    getchar(); // Consume newline character

    printf("  Last name: ");
    fgets(book->authors[i].last_name, MAX_NAME, stdin);
    book->authors[i].last_name[strcspn(book->authors[i].last_name, "\n")] = '\0';
  }

  printf("Please enter the price.\n");
  scanf("%f", &book->value);
}

// Function to print book details
void printBookDetails(struct Book book) {
  printf("%s \nAuthored by : ", book.title);
  // Print author names with commas
  for (int i = 0; i < book.num_authors; i++) {
    printf(" %s %c %s%s", book.authors[i].first_name,
           book.authors[i].middle_initial, book.authors[i].last_name,
           i < book.num_authors - 1 ? "," : ""); // Comma for all except last
  }
  printf("\n Price Rs. %.2f\n", book.value);
}
```

Lets discuss the `readBookDetails` functions used in this program.

The function header is `void readBookDetails(struct Book *book)`

It takes pointer to a `struct Book` variable as an argument.

This function is responsible for reading details about a book from the user and storing them in the provided `struct Book` variable.

Notice that it accepts the address to the `struct Book` variable, because whatever assignment operations this function does should reflect on the `struct Book book1` variable that `main()` passes to `readBookDetails` .

The argument `struct Book book1` has been ***passed-by-reference*** or you can say that the function has been ***called-by-reference***.

Let's take a closer look at this function.

```c
void readBookDetails(struct Book *book) {
  printf("Please enter the book title.\n");
  fgets((*book).title, MAX_TITLE, stdin);
  book->title[strcspn(book->title, "\n")] = '\0'; // Remove trailing newline

  printf("Enter the number of authors (up to %d): ", MAX_AUTHORS);
  scanf("%d", &(*book).num_authors);
  getchar(); // Consume newline character

  // Get information for each author
  for (int i = 0; i < book->num_authors && i < MAX_AUTHORS; i++) {
    printf("Enter details for author %d:\n", i + 1);
    printf("  First name: ");
    fgets(book->authors[i].first_name, MAX_NAME, stdin);
    book->authors[i].first_name[strcspn(book->authors[i].first_name, "\n")] = '\0';

    printf("  Middle initial (or hit space and enter if none): ");
    scanf("%c", &book->authors[i].middle_initial);
    getchar(); // Consume newline character

    printf("  Last name: ");
    fgets(book->authors[i].last_name, MAX_NAME, stdin);
    book->authors[i].last_name[strcspn(book->authors[i].last_name, "\n")] = '\0';
  }

  printf("Please enter the price.\n");
  scanf("%f", &book->value);
}
```

1. It asks for the number of authors contributing to the book, reads it with `scanf`.
    
    `scanf` needs the address of `num_authors`. We can find the address using the `&` operator.
    
    But where is `num_authors`? How can we access it?
    
    `num_authors` is inside the `struct Book book1` variable inside `main()`
    
    How can we access it from inside the `readBookDetails()` function?
    
    Using the `struct Book *book` parameter inside `readBookDetails()` !
    
    `struct Book *book` has the address of the `struct Book book1` variable inside `main()` .
    
    ```c
    readBookDetails(&book1);
    ```
    
    To reach from `struct Book *book` to the `struct Book book1` variable inside `main()` we have to ***dereference*** the book variable:
    
    `*book` is equivalent to `book1`
    
    Now next step would be to access the `num_authors` member using the dot operator.
    
    `(*book).num_authors`
    
    Note that we need the parentheses around `*book` because the dot operator has more precedence than the ***dereferencing***`*` operator that is used on `book` .
    
    And then we can finally find the address of `num_authors` using the `&` operator, so that `scanf` knows where to store the input value.
    
    ```c
    scanf("%d", &(*book).num_authors);
    ```
    
2. `getchar()` consumes the newline character left in the input buffer.
    
3. Now notice the header of the `for` loop.
    
    ```c
    for (int i = 0; i < book->num_authors && i < MAX_AUTHORS; i++)
    ```
    
    `(*book).num_authors` can be written in short using the ***arrow operator:***
    
    `book->num_authors`
    
4. It iterates over the number of authors provided by the user, prompting for each author's details individually:
    
    * First name is read using `fgets`.
        
    * Middle initial is read using `scanf`.
        
    * Last name is read using `fgets`.
        
5. Finally, it prompts the user to enter the book's price and reads it using `scanf`.
    

Now lets take a look at the `void printBookDetails(struct Book book)`

This function prints the details of a book provided as an argument.

So this function need not have access to the address of `struct Book` variable.

The argument has been ***passed-by-value*** or you can say that the function has been ***called-by-value***.

1. It prints the title of the book using `printf`.
    
2. It iterates over the authors of the book:
    
    * Prints each author's first name, middle initial, and last name using `printf`.
        
    * A comma is printed between authors, except for the last one.
        
3. It prints the price of the book using `printf`.
    

Output:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1711343040087/cfa1b5f1-9bd6-49f3-968b-6119bc715d83.png align="center")
