I'm trying to develop a C program that calculates the resistor values by inputting the colour bands marked on the resistor.
Ignoring the resistor tolerance.
e.g.
Enter the colours of the resistor’s three bands, beginning
with the band nearest the end. Type the colours in lowercase
letters only, NO CAPS
Band 1 => green
Band 2 => black
Band 3 => yellow
Resistance value: 500 000 -ohms
Do you want to decode another resistor (Y/N)?
=> Y
- Displaying the required format of the resistor value. For example, if the resistor value is "500000 -ohms", the format is required to be "500 000 -ohms". A space has to be put between every 3 digits.
- Displaying a single invalid colour. For example, if 'brown', 'vilet', and 'red' are inputted as the resistor colours, the program generates the following message:
Invalid colour: vilet
Here only 'vilet' is the only invalid colour.- Displaying more than one invalid colour. For example, if 'pink', 'silver', and 'red' are inputted as the resistor colours, the program should generate the following message in a single line:
Invalid colours: pink, silver
Here are two invalid colours 'pink' and 'silver'. Note the 'colours'.
Now I'm having a difficult time with getting the formatting for the total resistance (#1). And for #2 & #3 if and only if the first input (band 1) is invalid the program will run. If the second band or third band are invalid without the first band being invalid, the program will stop execution.
Here is the code that I've been working on:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
// resister bands
enum resistor_band_items {BLACK, BROWN, RED, ORANGE, YELLOW, GREEN, BLUE, VIOLET, GRAY, WHITE, UNKNOWN};
struct items
{
char *name;
enum resistor_band_items id;
} item_list[] = {
{"black", BLACK},
{"brown", BROWN},
{"red", RED},
{"orange", ORANGE},
{"yellow", YELLOW},
{"green", GREEN},
{"blue", BLUE},
{"violet", VIOLET},
{"gray", GRAY},
{"white", WHITE}
};
char answer[10], status[1] = "Y"; //answer => user input
char bands[3][10]; //string for resistor bands
//variables to hold the band values
int colour[3];
//function prototype
int inputVal (int *a, char b[3][10]);
double calResistance (int a, int b, int c);
void print_number (double number);
int main(void)
{
int i, invalid; //counter
double resistor_value; //total resistance value
enum resistor_band_items mid;
struct items *choice = NULL;
while (strcmp(status, "Y") == 0)
{
//print the question to the user
printf("Enter the colours of the resistor's three bands,\nbeginning with the band nearest to the end.\nType the coloues in lowercase letters only, NO CAPS.\n");
for (int j = 0; j<3; j++)
{
printf("Band %d => ", j + 1);
gets(answer);
for (i = 0, choice = NULL; i < sizeof item_list/sizeof(struct items); ++i)
{
if (strcmp(answer, item_list[i].name) == 0)
{
choice = item_list + i;
break;
}
}
mid = choice ? choice ->id : UNKNOWN;
colour[j] = mid;
strcpy(bands[j], answer);
}
invalid = inputVal (colour, bands);
if (invalid == 0)
{
//calculate resistor value
resistor_value = calResistance(colour[0], colour[1],colour[2]);
// print resistor value to user
printf("%.0f\n", resistor_value);
print_number(resistor_value);
}
printf("Do you want to decode another resistor (Y/N)?\n");
gets(status);
if (strcmp(status, "Y") == 0);
else break;
}
return 0;
}
int inputVal (int *a, char b[3][10])
{
int counter = 0, index[3];
for (int i = 0; i < 3; ++i)
{
if (a[i] == 10)
{
index[i] = i;
//printf("%s%s", b[i], " ");
counter++;
}
}
if (counter == 0)
{
return 0;
}
else if (counter == 1)
{
printf("Invalid colour: %s\n", b[index[0]]);
}
else if (counter == 2)
{
printf("Invalid colours:");
printf(" %s", b[index[0]]);
printf(",");
printf(" %s\n", b[index[1]]);
}
else
{
printf("Invalid colours:");
printf(" %s", b[index[0]]);
printf(",");
printf(" %s", b[index[1]]);
printf(",");
printf(" %s\n", b[index[2]]);
}
return 1;
}
double calResistance (int a, int b, int c)
{
double results;
unsigned power = 10;
while (b >= power)
{
power *= 10;
}
results = a * power + b;
results = results * pow(10, c);
return results;
}
void print_number (double number)
{
double n = number, *x;
int c = 0;
int j = 1;
while (n != 0 && n > 1)
{
n /= 10.0;
c += 1;
}
x = malloc (c * sizeof(double));
printf("%d\n", c);
for (int i = 0; i <= c; i++)
{
double digit = fmod (number, 10.0);
x[i] = digit;
number /= 10.0;
}
printf("Resistance value: \n\n");
for (int i = c - 1; i >= 0; i--)
{
printf("#%d = %.0f\n",i, x[i]);
}
printf("\n\n\n");
for (int i = c - 1; i >= 0; i--)
{
if (j == 3 || j == 7 || j == 11 || j == 15)
{
printf(" ");
}
else
{
printf("%.0f", x[i]);
}
j++;
}
printf(" -ohms\n");
//free(x);
}
I've edited the print_number function so it prints a space every 3rd digit. (It works with most combinations)
void print_number (double number)
{
double n = number, *x;
int c = 0;
int j = 1;
while (n != 0 && n > 1)
{
n /= 10.0;
c += 1;
}
x = malloc (c * sizeof(double));
printf("c = %d\n", c);
for (int i = 0; i < c; i++)
{
double digit = fmod (number, 10.0);
x[i] = digit;
number /= 10.0;
}
printf("Resistance value: \n");
for (int i = c; i >= 0; i--)
{
printf("#%d = %.0f\n",i, x[i]);
}
printf("\n\n");
printf("remainder of c = %d\n\n",c%3);
if (c % 3 == 2)
{
for (int i = c; i >= 0; i--)
{
if (j == 4 || j == 7 || j == 11 || j == 15)
{
printf(" ");
i++;
}
else
{
printf("%.0f", x[i]);
}
j++;
}
printf(" -ohms\n");
}
else
{
for (int i = c - 1 ; i >= 0; i--)
{
//printf("%.0f", x[i]);
if (c % 3 == 0)
{
if (j == 4 || j == 8 || j == 12 || j == 16)
{
printf(" ");
i++;
}
else
{
printf("%.0f", x[i]);
}
}
else if (c % 3 == 1)
{
if (j == 2 || j == 6 || j == 10 || j == 14)
{
printf(" ");
i++;
}
else
{
printf("%.0f", x[i]);
}
}
j++;
}
printf(" -ohms\n");
//free(x);
}
}
Rev 2
Here the modified code from the answers.
The reason I'm not using argc
and argv
is that the client has a restricted formatting that needs to be followd (Which drives me mad!)
here is the code:
//importing required header files
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
// resister bands
enum resistor_band_items {BLACK, BROWN, RED, ORANGE, YELLOW, GREEN,
BLUE, VIOLET, GRAY, WHITE, UNKNOWN};
//constants for min/max colour arguments and max colour char
enum {MINC = 3, MAXC = 4, MAXCC = 8};
struct items
{
char *name;
enum resistor_band_items id;
} item_list[] = {
{"black", BLACK},
{"brown", BROWN},
{"red", RED},
{"orange", ORANGE},
{"yellow", YELLOW},
{"green", GREEN},
{"blue", BLUE},
{"violet", VIOLET},
{"gray", GRAY},
{"white", WHITE}
};
//resistor multiplier values
int multiplier[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000};
char answer[3][10]; // User input
int colour_val[3]; //stores the band value
#define nItems (sizeof item_list/sizeof *item_list)
//function prototyps
int srchItems (char *ccode); //a search for index values
char *strcpy2lower (char *dest, char *src); //converts to lower case
int scmp (char *a, char *b); //simple string comarison
char *sepnumber (char *s, long val);
int invalid (char answer[3][10]);
//main function
int main(int argc, char const *argv[])
{
int i; // counter
char status = 'Y';// Keeps the program running when user inputs 'Y'
long resistor_value = 0; //Total resistance
int r, err, mult; //holds the significant figure, Error, Multiplier
char resistor_value_string[20] = "";//formatted output
while (status == 'Y') //The program runs under this
{
//print the question to the user
printf("Enter the colours of the resistor's three bands,\nbeginning with the band nearest to the end.\nType the coloues in lowercase letters only, NO CAPS.\n");
for (i = 0; i < MINC; ++i)
{
printf("Band %d => ", i + 1); // print headers for each band
scanf(" %s", &answer[i]); // get the user input
}
for (i = 0; i < MINC - 1; ++i) //converts colours into index
{
if ((r = srchItems (answer[i])) > -1)
{
// from significant figure
resistor_value = (resistor_value * 10) + r;
}
else
{
invalid(answer);
err = 2;
}
}
if (err > 1)
{
printf("Do you want to decode anothe resistor (Y/N)?\n");
scanf (" %c", &status);
if (status == 'Y');
else break;
}
else
{
mult = srchItems (answer[i]); // get multiplier index
resistor_value *= multiplier[mult]; // Calculate final value
sepnumber (resistor_value_string, resistor_value);
printf("Resistor value: ");
/*for (int i = 0; i < (strlen(resistor_value_string) ); ++i)
{
printf("%c", resistor_value_string[i]);
}
*/
puts (resistor_value_string);
//printf(" -ohm\n");
//memset (resistor_value_string, 0, 50);
printf("Do you want to decode anothe resistor (Y/N)?\n");
scanf (" %c", &status);
if (status == 'Y');
else break;
/*Debug
for (int i = 0; i < MINC; ++i)
{
printf("item_list[%d] = %s\n", i, answer[i]);
}
printf("Total resistance = %ld\n", resistor_value);
//end of debug */
}
}
return 0;
}
int srchItems (char *ccode)
{
int i;
char lccode [MAXCC] = "";
strcpy2lower (lccode, ccode); // converts everything to lower case
for (int i = 0; i < (int)nItems; ++i)
if (*lccode == *(item_list[i].name))
if (!scmp(item_list[i].name, lccode))
return i;
return -1;
}
char *strcpy2lower (char *dest, char *src)
{
if (!src || !dest) return NULL;
char *d = dest;
for (; *src; src++, d++)
if ('A' <= *src && *src <= 'Z')
*d = *src | (1 << 5);
else
*d = *src;
*d = 0;
return dest;
}
int scmp (char *a, char *b)
{
if (!a && !b) return 0;
if ( a && !b) return 1;
if (!a && b) return -1;
for (; *a && *b && *a == *b; a++, b++) {}
return *a - *b;
}
/** separate long value every 3rd char into 's' */
char *sepnumber (char *s, long val)
{
char numstr[3 * MAXCC] = "";
char *p = numstr;
size_t idx = 0, len = 0;
sprintf (numstr, "%ld", val);
for (; *p; p++) {}
len = p - numstr;
p = s + 3 * MAXCC - 2;
while (len--) {
if (idx++ == 3) {
idx = 1;
*p-- = ' ';
}
*p = numstr[len];
if (len) p--;
}
for (idx = 0; *p; p++, idx++) s[idx] = *p; /* copy to s */
s[idx] = *p; /* nul-terminate */
return s;
}
int invalid (char answer[3][10])
{
int r, counter = 0, incorrect[3], i;
for (i = 0; i < MINC; ++i)
{
if ((r = srchItems (answer[i])) == -1)
{
incorrect[i] = r;
counter++;
}
}
if (counter == 1)
{
printf("%s","Invalid colour: " );
printf("%s ", answer[i]);
printf("\n");
}
i = 0;
}
This rev works well for the first loop, but it calculates the wrong resistor value on the second loop onwards. It will print the invalid entries with a little difficulty! After an invalid colour is inputted the program will not calculate any resistor values.
out put examples:
$ ./RQ1.exe
Enter the colours of the resistor's three bands,
beginning with the band nearest to the end.
Type the coloues in lowercase letters only, NO CAPS.
Band 1 => red
Band 2 => orange
Band 3 => green
Resistor value: 2 300 000
Do you want to decode anothe resistor (Y/N)?
Y
Enter the colours of the resistor's three bands,
beginning with the band nearest to the end.
Type the coloues in lowercase letters only, NO CAPS.
Band 1 => green
Band 2 => black
Band 3 => yellow
Resistor value: -2 101 970 656
Do you want to decode anothe resistor (Y/N)?
Y
Enter the colours of the resistor's three bands,
beginning with the band nearest to the end.
Type the coloues in lowercase letters only, NO CAPS.
Band 1 => read
Band 2 => gren
Band 3 => blu
Do you want to decode anothe resistor (Y/N)?
Y
Enter the colours of the resistor's three bands,
beginning with the band nearest to the end.
Type the coloues in lowercase letters only, NO CAPS.
Band 1 => red
Band 2 => orange
Band 3 => green
Do you want to decode anothe resistor (Y/N)?
N
Final Rev,
I think this is it:) beside the fact that it still has problem displaying the invalid inputs.
A really big tanks to David C. Rankin for helping out so much.
#include <stdio.h>
#include <string.h>
#define nItems (sizeof item_list/sizeof *item_list)
char status = 'Y';
//
enum {MINC = 3, MAXCC = 10};
// resister bands
enum resistor_band_items {BLACK, BROWN, RED, ORANGE, YELLOW, GREEN,
BLUE, VIOLET, GRAY, WHITE, UNKNOWN};
struct items
{
char *name;
enum resistor_band_items id;
} item_list[] = {
{"black", BLACK},
{"brown", BROWN},
{"red", RED},
{"orange", ORANGE},
{"yellow", YELLOW},
{"green", GREEN},
{"blue", BLUE},
{"violet", VIOLET},
{"gray", GRAY},
{"white", WHITE}
};
unsigned int multiplier[] = {1, 10, 100, 1000, 10000, 100000, 1000000,
10000000, 100000000, 1000000000};
int srchItems (char *ccode); //a search for index values
char *strcpy2lower (char *dest, char *src); //converts to lower case
int scmp (char *a, char *b); //simple string comarison
char *sepnumber (char *s, long val); //puts space every 3rd digit
int main(void)
{
int i, error = 0, mult;
char input[MINC][MAXCC]; //user input
char invalid[MINC][MAXCC]; // invalid enteries
int colour_val[MINC]; //stores the band value
long total_resistance = 0;
char resistor_value_string[20] = "";//formatted output
do
{
//prompt user
printf("%s\n%s\n%s\n",
"Enter the colours of the resistor's three bands,",
"beginning with the band nearest to the end.",
"Type the colours in lowercase letters only, NO CAPS.");
for (i = 0; i < MINC; ++i)
{
printf("Band %d => ", i + 1); // print headers for each band
scanf(" %s", &input[i]); // get the user input
// converts user input to index of colours
colour_val[i] = srchItems(input[i]);
}
for (i = 0; i < MINC; ++i)
{
if (colour_val[i] == -1)
{
strcpy(invalid[i], input[i]);
error++;
}
}
if (error > 0)
{
if (error == 1)
{
printf("Invalid colour: %s\n", invalid[0]);
}
else if (error == 2)
{
printf("Invalid colours: %s, %s\n", invalid[0], invalid[1]);
}
else
{
printf("Invalid colours: %s, %s, %s\n",
invalid[0], invalid[1], invalid[2]);
}
}
else
{
//
for (i = 0; i < MINC - 1; ++i)
{
total_resistance = (total_resistance * 10) + colour_val[i];
}
mult = colour_val[2];
total_resistance *= multiplier[mult];
sepnumber (resistor_value_string, total_resistance);
printf("Resistance value: %s -Ohms\n", resistor_value_string);
//debug
for (i = 0; i < MINC; ++i)
{
//printf("Input ==> %s\t", input[i]);
//printf("index ==> %d\n", colour_val[i]);
}
//end debug
}
error = 0;
total_resistance = 0;
for (i = 0; i < MINC; ++i)
{
colour_val[i] = 0;
}
//ask user if they want to continue
printf("Do you want to decode another resistor?\n");
scanf(" %c", &status);
if (status == 'Y');
else break;
} while (status == 'Y');
return 0;
}
int srchItems (char *ccode)
{
int i;
char lccode [MAXCC] = "";
strcpy2lower (lccode, ccode); // converts everything to lower case
for (int i = 0; i < (int)nItems; ++i)
if (*lccode == *(item_list[i].name))
if (!scmp(item_list[i].name, lccode))
return i;
return -1;
}
char *strcpy2lower (char *dest, char *src)
{
if (!src || !dest) return NULL;
char *d = dest;
for (; *src; src++, d++)
if ('A' <= *src && *src <= 'Z')
*d = *src | (1 << 5);
else
*d = *src;
*d = 0;
return dest;
}
int scmp (char *a, char *b)
{
if (!a && !b) return 0;
if ( a && !b) return 1;
if (!a && b) return -1;
for (; *a && *b && *a == *b; a++, b++) {}
return *a - *b;
}
/** separate long value every 3rd char into 's' */
char *sepnumber (char *s, long val)
{
char numstr[3 * MAXCC] = "";
char *p = numstr;
size_t idx = 0, len = 0;
sprintf (numstr, "%ld", val);
for (; *p; p++) {}
len = p - numstr;
//printf("%d\n", len);
p = s + 3 * MAXCC - 2;
while (len--) {
if (idx++ == 3) {
idx = 1;
*p-- = ' ';
}
*p = numstr[len];
if (len) p--;
}
for (idx = 0; *p; p++, idx++) s[idx] = *p; /* copy to s */
s[idx] = *p; /* nul-terminate */
return s;
}
Output example
$ ./Q1_token.exe
Enter the colours of the resistor's three bands,
beginning with the band nearest to the end.
Type the colours in lowercase letters only, NO CAPS.
Band 1 => green
Band 2 => black
Band 3 => yellow
Resistance value: 500 000 -Ohms
Do you want to decode another resistor?
Y
Enter the colours of the resistor's three bands,
beginning with the band nearest to the end.
Type the colours in lowercase letters only, NO CAPS.
Band 1 => red
Band 2 => orange
Band 3 => green
Resistance value: 2 300 000 -Ohms
Do you want to decode another resistor?
Y
Enter the colours of the resistor's three bands,
beginning with the band nearest to the end.
Type the coloues in lowercase letters only, NO CAPS.
Band 1 => pink
Band 2 => silver
Band 3 => red
Invalid colours: pink, silver
Do you want to decode another resistor?
Y
Enter the colours of the resistor's three bands,
beginning with the band nearest to the end.
Type the colours in lowercase letters only, NO CAPS.
Band 1 => vilot
Band 2 => brown
Band 3 => read
Invalid colours: vilot, silver
Do you want to decode another resistor?
N
I think your code for number printing is too complex. Look at following code:
It's quick and dirty. Polish it.
Your code for determining the significant figures in your resistor value is quite a bit more complex than needed. Since you declare the global array of struct
item_list
, all you need to do to form the significant figure is to useitem_list
as a lookup-table to find the index for the band-color entered. For each subsequent color (2nd [and 3rd for 5-band]), you simply multiply the current resistor value by10
before adding the index.For example with the
item_list
index variabler
and the resistor valuerval
(including your check for an invalid color), your code could be reduced to:Above your
srchitems
function simply returns the index initem_list
given a color (entered as arguments to the program, e.g.argv[1]
,argv[2]
, ...) You can write a simplesrchitems
that converts all input to lowercase before preforming the lookup as:If you put the remaining pieces of the puzzle together, you could do something similar to the following. I leave it to you to format the output as needed. You can replace the simple string comparison function
scmp
withstrcmp
(and includestring.h
) Let me know if you have any questions.Example Use/Output
Valid resistor colors (uppercase or lowercase characters are fine)
Invalid colors generate individual errors:
Splitting Number Every 3rd char
Rather than a fairly complicated approach where you are relying on numeric calculations to test/separate your number, why not just convert your
number
to a string (without decimal places) and then simply work backwards from the end copying characters to a new string and add aspace
every 3rd character? It makes things a whole lot easier. (even though you are using adouble
for some unheard-of-reason -- assuming you will ultimately incorporate tolerance) It really makes no difference with this approach. Give the following a try:note, you can simply pass a character array to
print_number
and copyp
to the array if you want to make the array available back inmain
for formatting reasons (you can even changeprint_number
to returnchar *
in that case.) Let me know if it works. If you can't do it that way, then I'll work through your numeric logic, but that will take aspirin and will probably be in the morning:)
Example
print_number
OutputExample of Actual Implementation
Here is the way I implemented it into my code. Essentially, you just move
sepstr
declaration/initialization intomain
and then pass it as an array to yourprint_number
(mysepnumber
below).Example/Output
Reinitialize Values When Looping for Input
Given your description of the problem, I strongly suspect the issue you are having is due to not resetting/reinitializing
rval = 0;
(yourresistor_value
) at the end of each loop (or some similar value). Always check which values may be additive, etc. and remember to reset those values at the beginning of each loop. Another way to handle this in most cases is to declare the variables within the scope of the loop so that they are automatically reinitialized each iteration.Using block scope for the loop, your
main
should be similar to the following:Example Use/Output
I suspect you can find your error with this hint.