c – Want to know how to divide my code into separate functions

Since you are learning C, there are several considerations with your existing code. Your real question seems to be “How to divide my code into separate functions”.

There are two basic approaches,

  1. when learning, it’s often easier to write your program, get it debugged and working and then separate the like functionality into separate functions, or as your experience grows
  2. You understand the functionality you need to create and how it will interface with your existing code, and simply write a new function to meet your needs.

In your case, writing your program and then with it in front of you so you can separate the Input, Computationsand Output functionality will give you a good roadmap of what you need your functions to do.

In writing your program the first time, the considerations you may want to take to improve your code (here and going forward) are listed in the comments below:

#include <stdio.h>
#include <string.h>

#define N        2          /* define as many as you need - UPPERCASE */
#define MAXC    30
#define BUFSZ 1024

typedef struct products {   /* add a typedef to make type use convenient */
  char name[MAXC];
  char brand[MAXC];
  double price;
  int quantity;
} products;

int main (void)
{
  char buf[BUFSZ] = "";             /* read buffer */
  int i = 0;
  double sum = 0., avg = 0.;
  products products_arr[N] = {0};   /* initialize arrays all zero */
  
  puts ("Enter products");          /* heading before loop */
  
  for (i = 0; i < N; i++)
  {
    fputs ("n  Enter product name     : ", stdout);
    /* read user input with fgets() to consume entire line */
    if (fgets (products_arr[i].name, MAXC, stdin) == NULL) {
      puts ("(user canceled input)");
      return 0;
    }
    /* trim trailing 'n' with strcspn()
     *   strcspn (string, "n")               // returns no. of chars to "n"
     *   string[strcspn (string, "n")] = 0;  // overwrites 'n' with 0
     */
    products_arr[i].name[strcspn (products_arr[i].name, "n")] = 0;
    
    fputs ("  Enter product brand    : ", stdout);
    if (fgets (products_arr[i].brand, MAXC, stdin) == NULL) {
      puts ("(user canceled input)");
      return 0;
    }
    products_arr[i].brand[strcspn (products_arr[i].brand, "n")] = 0;

    fputs ("  Enter product price    : ", stdout);
    if (fgets (buf, MAXC, stdin) == NULL) {   /* read all input with fgets */
      puts ("(user canceled input)");
      return 0;
    }
    /* parse needed information from read-buffer with sscanf() */
    if (sscanf (buf, "%lf", &products_arr[i].price) != 1) {
      fputs ("error: invalid double value.n", stderr);
      return 1;
    }

    fputs ("  Enter product quantity : ", stdout);
    if (fgets (buf, MAXC, stdin) == NULL) {   /* read all input with fgets */
      puts ("(user canceled input)");
      return 0;
    }
    if (sscanf (buf, "%d", &products_arr[i].quantity) != 1) {
      fputs ("error: invalid integer value.n", stderr);
      return 1;
    }
  }

  for (i = 0; i < N; i++)
  { /* add 'n' to end of format string, don't call printf() twice */
    printf ("n%s - %s - %.2lf - %dn", products_arr[i].name,
            products_arr[i].brand,
            products_arr[i].price,
            products_arr[i].quantity);
    sum += products_arr[i].price;       /* don't waste loop, sum here */
  }

  avg = sum / N;
  printf("nAverage = %.2fn", avg);    /* always end final output with n */
}

Separating The Code Into Functions

With the roadmap of Input, Computationsand Output For the initial look at breaking your code into separate functions, you can fairly easily identify the input related code — as well as what variables are needed for it.

You have a maximum array size of N, you will need to pass as a parameter to your input function is the array of products. The input function can then return the number of products read (which can be less than N). On error you can return a negative values, or simply return the number of products successfully read at the time the error occurs, preserving the data you have collected at that point.

For your input function, you could do something like:

/** read up to a max of N products from stdin
 *  return number of elements read on success (can be less than N),
 *  otherwise returns -1 if user cancels input with manual EOF
 */
int read_products (products *products_arr)
{
  char buf[BUFSZ] = "";             /* read buffer */
  int i = 0;
  
  puts ("Enter products");          /* heading before loop */
  
  for (i = 0; i < N; i++)
  {
    fputs ("n  Enter product name     : ", stdout);
    /* read user input with fgets() to consume entire line */
    if (fgets (products_arr[i].name, MAXC, stdin) == NULL) {
      puts ("(user canceled input)");
      return 0;
    }
    /* trim trailing 'n' with strcspn()      // How?
     *   strcspn (string, "n")               // returns no. of chars to "n"
     *   string[strcspn (string, "n")] = 0;  // overwrites 'n' with 0
     */
    products_arr[i].name[strcspn (products_arr[i].name, "n")] = 0;
    
    fputs ("  Enter product brand    : ", stdout);
    if (fgets (products_arr[i].brand, MAXC, stdin) == NULL) {
      puts ("(user canceled input)");
      return -1;
    }
    products_arr[i].brand[strcspn (products_arr[i].brand, "n")] = 0;

    fputs ("  Enter product price    : ", stdout);
    if (fgets (buf, MAXC, stdin) == NULL) {   /* read all input with fgets */
      puts ("(user canceled input)");
      return -1;
    }
    /* parse needed information from read-buffer with sscanf() */
    if (sscanf (buf, "%lf", &products_arr[i].price) != 1) {
      fputs ("error: invalid double value.n", stderr);
      return i;
    }

    fputs ("  Enter product quantity : ", stdout);
    if (fgets (buf, MAXC, stdin) == NULL) {   /* read all input with fgets */
      puts ("(user canceled input)");
      return i;
    }
    if (sscanf (buf, "%d", &products_arr[i].quantity) != 1) {
      fputs ("error: invalid integer value.n", stderr);
      return 1;
    }
  }
  
  return i;
}

For your average function, in addition to the array of products, you also need to pass the number of products contained in the array (since it can be less than N). You always match the return type of your function to the type of value being returned. Here you could do:

/** computes the average of nelem product price
 *  returns average
 */
double products_avg (products *products_arr, int nelem)
{
  int i = 0;                /* initialize variables */
  double sum = 0;
  
  for (; i < nelem; i++)    /* loop nelem times */
  {
    sum += products_arr[i].price;   /* sum price */
  }
  
  return sum / nelem;       /* return average */
}

And finally your output function can just print the individual products. Again, in addition to the array, you need to pass the number of products in the array. Since the output function need not return a value, it can be type void as there is no need for an indication of success/failure and you are not relying on any computed value being returned, eg

/** prints individual product's name, brand, price & quantity */
void products_print (products *products_arr, int nelem)
{
  int i = 0;                /* initialize variables */
  
  for (; i < nelem; i++)    /* loop nelem times */
  { /* add 'n' to end of format string, don't call printf() twice */
    printf ("n%s - %s - %.2lf - %dn", products_arr[i].name,
            products_arr[i].brand,
            products_arr[i].price,
            products_arr[i].quantity);
  }
}

Putting it altogether, your program separated into function could look like:

#include <stdio.h>
#include <string.h>

#define N        2          /* define as many as you need - UPPERCASE */
#define MAXC    30
#define BUFSZ 1024

typedef struct products {   /* add a typedef to make type use convenient */
  char name[MAXC];
  char brand[MAXC];
  double price;
  int quantity;
} products;

/* function prototypes (will go in header file later) */
int read_products (products *products_arr);
double products_avg (products *products_arr, int nelem);
void products_print (products *products_arr, int nelem);

int main (void)
{
  int nelem = 0;
  double avg = 0.;
  products products_arr[N] = {0};         /* initialize arrays all zero */
  
  nelem = read_products (products_arr);   /* read products assign return */
  
  if (nelem < 1) {      /* validate read_products return */
    return 1;
  }
  
  avg = products_avg (products_arr, nelem);   /* compute average */
  
  products_print (products_arr, nelem);   /* output products */
  
  printf("nAverage = %.2fn", avg);      /* always end final output with n */
}

/** read up to a max of N products from stdin
 *  return number of elements read on success (can be less than N),
 *  otherwise returns -1 if user cancels input with manual EOF
 */
int read_products (products *products_arr)
{
  char buf[BUFSZ] = "";             /* read buffer */
  int i = 0;
  
  puts ("Enter products");          /* heading before loop */
  
  for (i = 0; i < N; i++)
  {
    fputs ("n  Enter product name     : ", stdout);
    /* read user input with fgets() to consume entire line */
    if (fgets (products_arr[i].name, MAXC, stdin) == NULL) {
      puts ("(user canceled input)");
      return 0;
    }
    /* trim trailing 'n' with strcspn()      // How?
     *   strcspn (string, "n")               // returns no. of chars to "n"
     *   string[strcspn (string, "n")] = 0;  // overwrites 'n' with 0
     */
    products_arr[i].name[strcspn (products_arr[i].name, "n")] = 0;
    
    fputs ("  Enter product brand    : ", stdout);
    if (fgets (products_arr[i].brand, MAXC, stdin) == NULL) {
      puts ("(user canceled input)");
      return -1;
    }
    products_arr[i].brand[strcspn (products_arr[i].brand, "n")] = 0;

    fputs ("  Enter product price    : ", stdout);
    if (fgets (buf, MAXC, stdin) == NULL) {   /* read all input with fgets */
      puts ("(user canceled input)");
      return -1;
    }
    /* parse needed information from read-buffer with sscanf() */
    if (sscanf (buf, "%lf", &products_arr[i].price) != 1) {
      fputs ("error: invalid double value.n", stderr);
      return i;
    }

    fputs ("  Enter product quantity : ", stdout);
    if (fgets (buf, MAXC, stdin) == NULL) {   /* read all input with fgets */
      puts ("(user canceled input)");
      return i;
    }
    if (sscanf (buf, "%d", &products_arr[i].quantity) != 1) {
      fputs ("error: invalid integer value.n", stderr);
      return 1;
    }
  }
  
  return i;
}

/** computes the average of nelem product price
 *  returns average
 */
double products_avg (products *products_arr, int nelem)
{
  int i = 0;                /* initialize variables */
  double sum = 0;
  
  for (; i < nelem; i++)    /* loop nelem times */
  {
    sum += products_arr[i].price;   /* sum price */
  }
  
  return sum / nelem;       /* return average */
}

/** prints individual product's name, brand, price & quantity */
void products_print (products *products_arr, int nelem)
{
  int i = 0;                /* initialize variables */
  
  for (; i < nelem; i++)    /* loop nelem times */
  { /* add 'n' to end of format string, don't call printf() twice */
    printf ("n%s - %s - %.2lf - %dn", products_arr[i].name,
            products_arr[i].brand,
            products_arr[i].price,
            products_arr[i].quantity);
  }
}

Example Use/Output

Both examples work exactly the same and would produce the same output, such as:

$ ./bin/structavg
Enter products

  Enter product name     : foo
  Enter product brand    : fink
  Enter product price    : 23.44
  Enter product quantity : 10

  Enter product name     : bar
  Enter product brand    : blink
  Enter product price    : 26.66
  Enter product quantity : 10

foo - fink - 23.44 - 10

bar - blink - 26.66 - 10

Average = 25.05

Look things over and let me know if you have questions.

Leave a Comment