Skip to main content

Command Palette

Search for a command to run...

Modularizing our code with functions

Updated
•5 min read•View as Markdown
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.

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

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() .

     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.

     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.

     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:

28 views

More from this blog

P

Programming Tutorials

89 posts