Figure 11.12 Universal Measurement Conversion Program Using an Array of Structures /* * Converts measurements given in one unit to any other unit of the same * category that is listed in the database file, units.dat. * Handles both names and abbreviations of units. */ #include #include #define NAME_LEN 30 /* storage allocated for a unit name */ #define ABBREV_LEN 15 /* storage allocated for a unit abbreviation */ #define CLASS_LEN 20 /* storage allocated for a measurement class */ #define NOT_FOUND -1 /* value indicating unit not found */ #define MAX_UNITS 20 /* maximum number of different units handled */ typedef struct { /* unit of measurement type */ char name[NAME_LEN]; /* character string such as "milligrams" */ char abbrev[ABBREV_LEN];/* shorter character string such as "mg" */ char class[CLASS_LEN]; /* character string such as "pressure", "distance", "mass" */ double standard; /* number of standard units equivalent to this unit */ } unit_t; int fscan_unit(FILE *filep, unit_t *unitp); void load_units(int unit_max, unit_t units[], int *unit_sizep); int search(const unit_t units[], const char *target, int n); double convert(double quantity, double old_stand, double new_stand); int main(void) { unit_t units[MAX_UNITS]; /* units classes and conversion factors*/ int num_units; /* number of elements of units in use */ char old_units[NAME_LEN], /* units to convert (name or abbrev) */ new_units[NAME_LEN]; /* units to convert to (name or abbrev)*/ int status; /* input status */ double quantity; /* value to convert */ int old_index, /* index of units element where old_units found */ new_index; /* index where new_units found */ /* Load units of measurement database */ load_units(MAX_UNITS, units, &num_units); /* Convert quantities to desired units until data format error (including error code returned when q is entered to quit) */ printf("Enter a conversion problem or q to quit.\n"); printf("To convert 25 kilometers to miles, you would enter\n"); printf("> 25 kilometers miles\n"); printf(" or, alternatively,\n"); printf("> 25 km mi\n> "); for (status = scanf("%lf%s%s", &quantity, old_units, new_units); status == 3; status = scanf("%lf%s%s", &quantity, old_units, new_units)) { printf("Attempting conversion of %.4f %s to %s . . .\n", quantity, old_units, new_units); old_index = search(units, old_units, num_units); new_index = search(units, new_units, num_units); if (old_index == NOT_FOUND) printf("Unit %s not in database\n", old_units); else if (new_index == NOT_FOUND) printf("Unit %s not in database\n", new_units); else if (strcmp(units[old_index].class, units[new_index].class) != 0) printf("Cannot convert %s (%s) to %s (%s)\n", old_units, units[old_index].class, new_units, units[new_index].class); else printf("%.4f%s = %.4f %s\n", quantity, old_units, convert(quantity, units[old_index].standard, units[new_index].standard), new_units); printf("\nEnter a conversion problem or q to quit.\n> "); } return (0); } /* * Gets data from a file to fill output argument * Returns standard error code: 1 => successful input, 0 => error, * negative EOF value => end of file */ int fscan_unit(FILE *filep, /* input - input file pointer */ unit_t *unitp) /* output - unit_t structure to fill */ { int status; status = fscanf(filep, "%s%s%s%lf", unitp->name, unitp->abbrev, unitp->class, &unitp->standard); if (status == 4) status = 1; else if (status != EOF) status = 0; return (status); } /* * Opens database file units.dat and gets data to place in units until end * of file is encountered. Stops input prematurely if there are more than * unit_max data values in the file or if invalid data is encountered. */ void load_units(int unit_max, /* input - declared size of units */ unit_t units[], /* output - array of data */ int *unit_sizep) /* output - number of data values stored in units */ { FILE *inp; unit_t data; int i, status; /* Gets database of units from file */ inp = fopen("units.dat", "r"); i = 0; for (status = fscan_unit(inp, &data); status == 1 && i < unit_max; status = fscan_unit(inp, &data)) { units[i++] = data; } fclose(inp); /* Issue error message on premature exit */ if (status == 0) { printf("\n*** Error in data format ***\n"); printf("*** Using first %d data values ***\n", i); } else if (status != EOF) { printf("\n*** Error: too much data in file ***\n"); printf("*** Using first %d data values ***\n", i); } /* Send back size of used portion of array */ *unit_sizep = i; } /* * Searches for target key in name and abbrev components of first n * elements of array units * Returns index of structure containing target or NOT_FOUND */ int search(const unit_t units[], /* array of unit_t structures to search */ const char *target, /* key searched for in name and abbrev components */ int n) /* number of array elements to search */ { int i, found = 0, /* whether or not target has been found */ where; /* index where target found or NOT_FOUND */ /* Compare name and abbrev components of each element to target */ i = 0; while (!found && i < n) { if (strcmp(units[i].name, target) == 0 || strcmp(units[i].abbrev, target) == 0) found = 1; else ++i; } /* Return index of element containing target or NOT_FOUND */ if (found) where = i; else where = NOT_FOUND; return (where); } /* * Converts one measurement to another given the representation of both * in a standard unit. For example, to convert 24 feet to yards given a * standard unit of inches: quantity = 24, old_stand = 12 (there are 12 * inches in a foot), new_stand = 36 (there are 36 inches in a yard), * result is 24 * 12 / 36 which equals 8 */ double convert(double quantity, /* value to convert */ double old_stand, /* number of standard units in one of quantity's original units */ double new_stand) /* number of standard units in 1 new unit */ { return (quantity * old_stand / new_stand); }