I have recently started learning C in university and my task today was to write a program that calculates the average price of products in an array of structures. I was told that my code should be divided into separate functions. How do I put the printf for loop and the average price for loop in a separate function and then call it in the main()?
Thanks for the replies in advance.
#define n 2
struct products{
char name[30];
char brand[30];
double price;
int quantity;
};
int main()
{
struct products products_arr[n];
int i;
float sum,avg;
for (i=0;i<n;i )
{
printf("Enter product/s:\n\n");
printf("Enter product name: \n");
scanf("%s",products_arr[i].name);
printf("Enter product brand: \n");
scanf("%s",products_arr[i].brand);
printf("Enter product price: \n");
scanf("%lf",&products_arr[i].price);
printf("Enter product quantity: \n");
scanf("%d",&products_arr[i].quantity);
}
for (i=0;i<n;i )
{
printf("\n%s - %s - %.2lf - %d",products_arr[i].name,
products_arr[i].brand,
products_arr[i].price,
products_arr[i].quantity);
printf("\n");
}
for (i = 0; i < n; i )
{
sum = products_arr[i].price;
}
avg = sum / n;
printf("\nAverage = %.2f", avg);
return 0;
}
CodePudding user response:
heres how to do the avg function
double avg(struct products * prod, int sz){
double sum = 0;
for(int i = 0 ; i < sz; i ){
sum = prod[i].price;
}
return sum / sz;
}
note you have to pass a pointer to the start of the array , plus the size of the array
now call it in main
double average = avg(products_arr, n);
if the body of the function is after the body of main you will need a forward declarion of avg before main
double avg(struct products * prod, int sz);
you can use this as a model for doing the other functions
CodePudding user response:
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,
- 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
- 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, Computations, and 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 - %d\n", 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 = %.2f\n", avg); /* always end final output with \n */
}
Separating The Code Into Functions
With the roadmap of Input, Computations, and 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 you 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, e.g.
/** 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 - %d\n", 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 = %.2f\n", 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 - %d\n", 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.