I need to receive a single line of characters and convert them from the base they are written in to a decimal base, as soon as a character is typed.
I did this by using the following function:
int inToDec(int base) //My assumption is that Enter will not be pressed as the first character - if it is, I am not sure what to do in that case
{
int numdec=0, c;//decimalized number, a variable for character inpu
while((c = getchar()) != '\n' && c != EOF)
{
if(c >= 97)//Checks if the char is an actual char
c = c - 'a' - 1;
else//or a digit char
c = c;
numdec += numdec * base + c;//every time another char is inputted, it multiplies the numdec by the base and adds the char's value in decimal base - which is essentially the algorithm for conversion to decimal base.
}
return numdec;
}
My main():
#include <stdio.h>
#include "funcs.h"
int main()
{
int option, fbase, tbase, num1, num2;
do
{
scanf("%d",&option);
switch(option)
{
case 1:
scanf("%d",&fbase);
num1 = inToDec(fbase);
num2 = inToDec(fbase);
outFromDec(num1+num2,fbase);
break;
case 2:
scanf("%d",&fbase);
num1 = inToDec(fbase);
num2 = inToDec(fbase);
if(num1>=num2)
outFromDec(num1-num2,fbase);
else
outFromDec(num2-num1,fbase);
break;
case 3:
scanf("%d",&fbase);
scanf("%d",&tbase);
num1 = inToDec(fbase);
outFromDec(num1,tbase);
break;
}
}while(option != 4);
return 0;
}
Except that when I input the number(after the option and the desired base) and type Enter to continue to the next one, suddenly it starts to print a character time after time without end. What did I do wrong and how do I fix it? Or, if you do not want to explain some obvious fact to a noob, where do I read about it (preferably without too much heavy duty tech-talk, as I am relatively new to programming).
outFromDec() -
void outFromDec(int num, int base) //converts num into the base given and prints
{
int count = 0 , temp = num, i;
char c;
while(temp != 0)
{
temp /= base;
count++;
}
temp = num;
do
{
for(i=1;i<count;i++)
temp /= base;
if(temp<=9)
c = '0' + temp;
else
c = 'a' + temp - 1;
putchar(c);
count--;
temp = num / temp;
}while(temp != 0);
}
This code has problems:
while(c = getchar() != '\n' && c != EOF)
Not enough parentheses — assignment is a low priority operator. It should be:
while ((c = getchar()) != '\n' && c != EOF)
Another set of problems is in the conversion code in the body of the loop:
if (c >= 97)
c = c - 'a' - 1;
else
c = c;
numdec += numdec * base + c;
The choice of 97
is presumably the ASCII or ISO 8859-n or Unicode code point for a
. This ignores upper case letters, punctuation, and treats the digits 0
to 9
as though they 48..57. You probably need to use #include <ctype.h>
. It also does not validate that the 'digit' is valid for the base.
However, on the first call to intToDec()
, the first character read is a newline, left over by scanf()
, so the first number is always zero, if you enter the numbers one per line as you're told to.
When you finally get to outToDec()
, you have some interesting numerology. I added printf()
statements to track function entry and exit, and also for key points in the loop:
void outFromDec(int num, int base)
{
printf("-->> %s: %d %d\n", __func__, num, base);
int count = 0, temp = num, i;
char c;
while (temp != 0)
{
temp /= base;
count++;
}
printf("Count: %d\n", count);
temp = num;
do
{
printf("count: %d; temp = %d\n", count, temp);
for (i = 1; i < count; i++)
temp /= base;
if (temp <= 9)
c = '0' + temp;
else
c = 'a' + temp - 1;
putchar(c);
count--;
temp = num / temp;
} while (temp != 0);
printf("<<-- %s\n", __func__);
}
The __func__
is a predefined identifier in C99 containing the function name. It may not be available to you in MSVC; if not, replace it with the function name.
For the inputs 1
, 9
, 9
, the output from the program was:
-->> inToDec: 9
<<-- inToDec: 0
-->> inToDec: 9
<<-- inToDec: 57
-->> outFromDec: 57 9
Count: 2
count: 2; temp = 57
6count: 1; temp = 9
9count: 0; temp = 6
6count: -1; temp = 9
9count: -2; temp = 6
And the count continued to decrease and the 6's and 9's continued to alternate. You seem to be trying to isolate the digits with the most significant digit (MSD) discovered first. The loop determining count
is correct; the loop printing the digits clearly isn't. You should be able to take it from there; it is routine debugging. Note how I used the print statements to see what was going on. If you can't resolve it by just looking at the code, print out the result of every expression, if necessary.
I observe that to print 57 in base 10, you'd discover that there are 2 digits to print (count == 2
). The first digit would be found by dividing by the base (10) count-1
times; this would give you 5 to print. You probably need to subtract 5 * 10 from the number so that the next (in this case, the last) time around the loop, you'd start with just 7, which you'd print. The loop would stop. You should ensure the loop breaks if count
ever goes negative.
This is an expensive way of formatting a 10-digit 32-bit number (or even more so a 19-digit 64-bit number). It can be made to work, though. The standard procedure collects the digits in reverse order and arranges to print them out in the inverse order. (number % base
gives you the digit to be printed; number /= base
reduces the number of digits left to process.)
As happens quite often, the OP is under artificial constraints and may not use strings. Yuck!
Here is a 'read an integer' function that is plausibly robust. It does assume 2's complement arithmetic; it contains an assertion that should fire if it was ever run on a machine that was sign-magnitude or 1's complement (but I haven't tested it; I don't have any such machines available to test on).
Note that the code accumulates the number as a negative number, and makes it positive at the end if it should be positive. This makes it easier to deal with INT_MIN than trying to accumulate it as a positive int
.
For the purposes of the exercise, I'm treating the system as though sizeof(intmax_t) == sizeof(int)
(and hence sizeof(int) == sizeof(long)
and sizeof(int) == sizeof(long long)
too); this technique would work if the integer type were intmax_t
instead of int
. Note that the C standard does not rule out this supposed configuration (but the standard requires that CHAR_BIT * sizeof(int) >= 64
to be a conforming implementation).
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
/* Read an integer from stdin without prompt: code is not allowed to use strings! */
enum { E_OK = 0, E_EOF = -1, E_INVCHAR = -2, E_OVERFLOW = -3 };
extern int read_an_int(int *value);
int read_an_int(int *value)
{
int number = 0;
int c;
int pos_neg = +1;
assert(-INT_MAX != INT_MIN); // Probably 2's complement
while ((c = getchar()) != EOF && isspace(c))
;
if (c == '-')
{
pos_neg = -1;
c = getchar();
}
else if (c == '+')
{
pos_neg = +1;
c = getchar();
}
if (c == EOF)
return E_EOF;
if (!isdigit(c))
return E_INVCHAR;
number = '0' - c; /* Negated digit */
while ((c = getchar()) != EOF && isdigit(c))
{
int d = '0' - c; /* Negated digit */
if (number < INT_MIN / 10 || (number == INT_MIN/10 && d < INT_MIN % 10))
return E_OVERFLOW;
//printf("N1 %d; d %d; ", number, d);
number = number * 10 + d;
//printf("N2 %d\n", number);
}
if (c != EOF)
ungetc(c, stdin);
if (pos_neg != -1)
{
//printf("Should be switched (%d)(%d)\n", pos_neg, number);
if (number == INT_MIN)
return E_OVERFLOW;
number = -number;
//printf("Should be positive (%d)(%d)\n", pos_neg, number);
}
*value = number;
return E_OK;
}
static void gobble_input(void)
{
int c;
while ((c = getchar()) != EOF)
{
if (isdigit(c) || c == '+' || c == '-')
{
ungetc(c, stdin);
break;
}
printf("Skip %c\n", c);
}
}
int main(void)
{
int rc;
int number;
while ((rc = read_an_int(&number)) != E_EOF)
{
switch (rc)
{
case E_INVCHAR:
printf("Invalid character spotted\n");
gobble_input();
break;
case E_OVERFLOW:
printf("Input would have overflowed integer range %d..%d\n", INT_MIN, INT_MAX);
break;
case E_OK:
printf("Input number: %d\n", number);
break;
default:
assert(0);
break;
}
}
return 0;
}
The test data file I used was:
0
1
2
3
4
5
6
7
8
9
11
+123
1234
56789
+123456789
2147483647
2147483648
+000000123456789
000000123456789
-0000
+0000
-1
-2
-9
-21
-321
-4321
-2147483647
-2147483648
-2147483649
# Bogus data or partially bogus data
-
+
-213a
+213a
+.213
3.14159E+23
The output from that was:
Input number: 0
Input number: 1
Input number: 2
Input number: 3
Input number: 4
Input number: 5
Input number: 6
Input number: 7
Input number: 8
Input number: 9
Input number: 11
Input number: 123
Input number: 1234
Input number: 56789
Input number: 123456789
Input number: 2147483647
Input would have overflowed integer range -2147483648..2147483647
Input number: 123456789
Input number: 123456789
Input number: 0
Input number: 0
Input number: -1
Input number: -2
Input number: -9
Input number: -21
Input number: -321
Input number: -4321
Input number: -2147483647
Input number: -2147483648
Input would have overflowed integer range -2147483648..2147483647
Invalid character spotted
Skip
Skip B
Skip o
Skip g
Skip u
Skip s
Skip
Skip d
Skip a
Skip t
Skip a
Skip
Skip o
Skip r
Skip
Skip p
Skip a
Skip r
Skip t
Skip i
Skip a
Skip l
Skip l
Skip y
Skip
Skip b
Skip o
Skip g
Skip u
Skip s
Skip
Skip d
Skip a
Skip t
Skip a
Skip
Invalid character spotted
Invalid character spotted
Input number: -213
Invalid character spotted
Skip
Input number: 213
Invalid character spotted
Skip
Invalid character spotted
Input number: 213
Input number: 3
Invalid character spotted
Input number: 14159
Invalid character spotted
Input number: 23
Note that the last line provided 3 valid numbers (and two invalid characters, the .
and the E
).
It isn't particularly easy; that's why these things are coded in library functions. Also, the 'no strings' requirement means I can't do decent error reporting when there are invalid characters or overflows.