Amir Amir - 2 months ago 6
C Question

Calculating the resistor value with its color bands as input

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




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

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

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

Answer

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 use item_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 by 10 before adding the index.

For example with the item_list index variable r and the resistor value rval (including your check for an invalid color), your code could be reduced to:

int multiplier[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 };
...
    int err = 0, i, mult, r;
    long rval = 0;

    printf ("\ncolor bands determining significant figures:\n\n");
    for (i = 1; i < argc - 1; i++) { /* convert colors to index */
        if ((r = srchitems (argv[i])) != -1) {
            rval = rval * 10 + r;    /* form significant figure */
            prnitem (r);
        }
        else {
            fprintf (stderr, "error: invalid color '%s'\n", argv[i]);
            err = 1;
        }
    }
    if (err) return 1;
    mult = srchitems (argv[i]);     /* get multiplier index  */
    rval *= multiplier[mult];       /* calculare final value */
    printf ("\nmultiplier:\n\n");
    prnitem (mult);
    printf ("\nresistor value : %ld -ohms\n\n", rval);

    return 0;

Above your srchitems function simply returns the index in item_list given a color (entered as arguments to the program, e.g. argv[1], argv[2], ...) You can write a simple srchitems that converts all input to lowercase before preforming the lookup as:

/** search item_list for color code 'ccode', return index
 *  returns array index on success, -1 otherwise.
 */
int srchitems (char *ccode)
{
    int i;
    char lccode[MAXCC] = "";       /* array to hold lowercase color */

    strcpy2lower (lccode, ccode);  /* convert string to lowercase */

    for (i = 0; i < (int)nitems; i++)    /* lookup index */
        if (*lccode == *(item_list[i].name))
            if (!scmp (item_list[i].name, lccode))
                return i;

    return -1;   /* return -1 on error */
}

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 with strcmp (and include string.h) Let me know if you have any questions.

#include <stdio.h>

/* resister bands */
enum resistor_band_items { BLACK, BROWN, RED, ORANGE, YELLOW, GREEN, 
                        BLUE, VIOLET, GRAY, WHITE, UNKNOWN };
/* constants for min/max color arguments and max color chars */
enum { MINC = 3, MAXC = 4, MAXCC = 8 };

struct items    /* could be simple array of strings */
{
    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 };

#define nitems (sizeof item_list/sizeof *item_list)

int srchitems (char *ccode);
char *strcpy2lower (char *dest, char *src);
int scmp (char *a, char *b);
void prnitem (int i);

int main (int argc, char **argv) {

    if (argc < MAXC || MAXC + 1 < argc) { /* check 3 or 4 arguments */
        fprintf (stderr, "error: invalid input, usage: %s c1 c2 c3 [c4]\n"
                         "usage: enter color codes for 4 or 5-band resistor\n"
                         "       (tolerance ignored, enter 4 colors max)\n",
                        argv[0]);
        return 1;
    }

    int err = 0, i, mult, r;
    long rval = 0;

    printf ("\ncolor bands determining significant figures:\n\n");
    for (i = 1; i < argc - 1; i++) { /* convert colors to index */
        if ((r = srchitems (argv[i])) != -1) {
            rval = rval * 10 + r;    /* form significant figure */
            prnitem (r);
        }
        else {
            fprintf (stderr, "error: invalid color '%s'\n", argv[i]);
            err = 1;
        }
    }
    if (err) return 1;
    mult = srchitems (argv[i]);     /* get multiplier index  */
    rval *= multiplier[mult];       /* calculare final value */
    printf ("\nmultiplier:\n\n");
    prnitem (mult);
    printf ("\nresistor value : %ld -ohms\n\n", rval);

    return 0;
}

/** search item_list for color code 'ccode', return index
 *  returns array index on success, -1 otherwise.
 */
int srchitems (char *ccode)
{
    int i;
    char lccode[MAXCC] = "";

    strcpy2lower (lccode, ccode);

    for (i = 0; i < (int)nitems; i++)
        if (*lccode == *(item_list[i].name))
            if (!scmp (item_list[i].name, lccode))
                return i;

    return -1;
}

/** copy and convert string to lowercase.
 *  returns copy of string with all chars converted to lowercase.
 *  ('dest' must be of sufficient size of hold 'src')
 */
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;
}

/** simple string comparison (like strcmp) */
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;
}

void prnitem (int i)
{
    printf (" item_list[%d]  name: %-6s  id: %d\n", 
            i, item_list[i].name, item_list[i].id);
}

Example Use/Output

Valid resistor colors (uppercase or lowercase characters are fine)

$ ./bin/resistor green blue yellow

color bands determining significant figures:

 item_list[5]  name: green   id: 5
 item_list[6]  name: blue    id: 6

multiplier:

 item_list[4]  name: yellow  id: 4

resistor value : 560000 -ohms


$ ./bin/resistor Red Orange Violet Black

color bands determining significant figures:

 item_list[2]  name: red     id: 2
 item_list[3]  name: orange  id: 3
 item_list[7]  name: violet  id: 7

multiplier:

 item_list[0]  name: black   id: 0

resistor value : 237 -ohms

Invalid colors generate individual errors:

$ ./bin/resistor pink silver green

color bands determining significant figures:

error: invalid color 'pink'
error: invalid color 'silver'

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 a space every 3rd character? It makes things a whole lot easier. (even though you are using a double for some unheard-of-reason -- assuming you will ultimately incorporate tolerance) It really makes no difference with this approach. Give the following a try:

void print_number (double number)
{
    char numstr[3 * MAXCC] = "", sepstr[3 * MAXCC] = "";
    char *p = NULL;
    size_t idx = 0, len = 0;

    sprintf (numstr, "%.0lf", number);  /* write double to string */
    len = strlen (numstr);              /* get length */
    p = sepstr + 3 * MAXCC - 2;         /* set p at last char in sepstr */

    while (len--) {         /* for each char in numstr */
        if (idx++ == 3) {   /* if 3 characters copied  */
            idx = 1;        /* reset index */
            *p-- = ' ';     /* write a space in sepstr */
        }
        *p = numstr[len];   /* write char in sepstr    */
        if (len) p--;       /* decrement p if not at 0 */
    }

    printf ("p : '%s'\n", p);  /* print the separate value */
}

note, you can simply pass a character array to print_number and copy p to the array if you want to make the array available back in main for formatting reasons (you can even change print_number to return char * 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 Output

           5 => '5'
          55 => '55'
         555 => '555'
        5555 => '5 555'
       55555 => '55 555'
      555555 => '555 555'
     5555555 => '5 555 555'
    55555555 => '55 555 555'
   555555555 => '555 555 555'

Example of Actual Implementation

Here is the way I implemented it into my code. Essentially, you just move sepstr declaration/initialization into main and then pass it as an array to your print_number (my sepnumber below).

char *sepnumber (char *s, long val);
...
    long rval = 0;
    char rstr[3 * MAXCC] = "";
    ...
    printf ("\nresistor value : %s -ohms\n\n", sepnumber (rstr, rval));

    return 0;
}
...
/** 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;
}

Example/Output

$ ./bin/resistor green blue yellow

color bands determining significant figures:

 item_list[5]  name: green   id: 5
 item_list[6]  name: blue    id: 6

multiplier:

 item_list[4]  name: yellow  id: 4

resistor value : 560 000 -ohms


$ ./bin/resistor Red Orange Violet Brown

color bands determining significant figures:

 item_list[2]  name: red     id: 2
 item_list[3]  name: orange  id: 3
 item_list[7]  name: violet  id: 7

multiplier:

 item_list[1]  name: brown   id: 1

resistor value : 2 370 -ohms

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; (your resistor_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:

int main (void) {

    for (;;) {                      /* loop for input */
        int err = 0, i, mult, r;    /* variables have block scope only */
        long rval = 0;
        char ccode[MAXCC] = "", rstr[3 * MAXCC] = "";

        printf ("\nEnter the colours of the resistor's three bands,\n"
                "beginning with the band nearest to the end.\n");
        for (i = 0; i < MINC; i++) { /* convert colors to index */
            printf ("Band %d => ", i + 1);
            if (scanf (" %7s", ccode) != 1) {
                fprintf (stderr, "error: invalid input or EOF.\n");
                return 1;
            }
            if ((r = srchitems (ccode)) != -1) {
                if (i < 2) {
                    rval = rval * 10 + r;    /* form significant figure */
                }
                else {
                    mult = srchitems (ccode);  /* get multiplier index  */
                    rval *= multiplier[mult];  /* calculare final value */
                }
            }
            else {
                fprintf (stderr, "error: invalid color '%s'\n", ccode);
                err = 1;
            }
        }
        if (err) return 1;
        printf ("Resistor value : %s -ohms\n", sepnumber (rstr, rval));
        printf ("\nDo you want to decode another resistor (y/n)? ");
        if (scanf (" %7s", ccode) != 1) {
            fprintf (stderr, "error: invalid input or EOF.\n");
            return 1;
        }
        if (*ccode != 'y' && *ccode != 'Y') break;
    }

    return 0;
}

Example Use/Output

$ ./bin/resistor2

Enter the colours of the resistor's three bands,
beginning with the band nearest to the end.
Band 1 => green
Band 2 => blue
Band 3 => yellow
Resistor value : 560 000 -ohms

Do you want to decode another resistor (y/n)? y

Enter the colours of the resistor's three bands,
beginning with the band nearest to the end.
Band 1 => red
Band 2 => orange
Band 3 => orange
Resistor value : 23 000 -ohms

Do you want to decode another resistor (y/n)? n

I suspect you can find your error with this hint.

Comments