C: Use scanf() function instead of gets - c

/* hexadecimal to decimal conversion */
#include <stdio.h>
#include <math.h>
#include <string.h>
int main()
{
char hex[17];
long long decimal;
int i , val, len;
decimal = 0;
// Input hexadecimal number from user
printf("Enter any hexadecimal number: ");
gets(hex);
//Find the length of total number of hex digit
len = strlen(hex);
len--;
for(i=0; hex[i]!='\0'; i++)
{
// Find the decimal representation of hex[i]
if(hex[i]>='0' && hex[i]<='9')
{
val = hex[i] - 48;
}
else if(hex[i]>='a' && hex[i]<='f')
{
val = hex[i] - 97 + 10;
}
else if(hex[i]>='A' && hex[i]<='F')
{
val = hex[i] - 65 + 10;
}
decimal += val * pow(16, len);
len--;
}
printf("Hexadecimal number = %s\n", hex);
printf("Decimal number = %lld", decimal);
return 0;
}
In the above program when i have used scanf instead of gets,it doesn't give the result.why? i used scanf("%x",hex); . please explain me decimal += val * pow(16, len); too.thank you so much in advance.

Because if you use scanf(), it does the conversion from string for you, that's sort of its entire point.
unsigned int x;
if(scanf("%x", &x) == 1)
printf("you entered %d (hex 0x%x)\n", x, x);
You can't combine %x a pointer to a character array, it requires a pointer to an unsigned integer. This is of course well documented in the manual page.
Also, using pow() here seems excessive, just multiply what you have by 16 before adding in each new digit:
unsigned int parsehex(const char *s)
{
unsigned int x = 0;
const char *digits = "0123456789abcdef";
const char *p;
while(*s && (p = strchr(digits, tolower(*s++))) != NULL)
{
x *= 16;
x += (unsigned int) (p - digits);
}
return x;
}
This is a bit "heavier" (uses strchr()) than your code, but shorter and perhaps therefore easier to validate. If it's overly performance-critical, I'd consider looking into it.

scanf("%x",hex);
should be
scanf("%s",hex);
you cannot do hex[i] when you read as integer.
decimal += val * pow(16, len); represents decimal = decimal + (val * pow(16, len));
Hopes this answers your question

scanf("%x"...) performs the conversion to integer for you. Therefore, you want to deposit the result in decimal:
scanf("%x", &decimal);
Each iteration of the for loop is generating a nibble (4 bits) of the number into val. The val * pow(16, len); is (in)effectively shifting the nibble into the correct position. However, this code is using floating point math to accomplish this (pow returns a double) instead of simply left shifting by 4*len. A better approach is to simply shift decimal left by 4 bits on each iteration and add (or OR) the nibble into the least significant bits. In this way, the first nibble will ultimately end up where it is supposed to be.
Also, character literals work as numbers, so instead of subtracting 48, 97, 65 it would read better if you subtracted '0', 'f', 'F' respectively.

Related

My decimal to hex conversion function only woks with positive nums

I'm having problems converting negative numbers, from decimal base to hexadecimal base, with the following function:
#include <stdio.h>
int main()
{
int quotient, remainder;
int i, j = 0;
char hexadecimalnum[100];
quotient = -50;
while (quotient != 0)
{
remainder = quotient % 16;
if (remainder < 10)
hexadecimalnum[j++] = 48 + remainder;
else
hexadecimalnum[j++] = 55 + remainder;
quotient = quotient / 16;
}
strrev(hexadecimalnum);
printf("%s", hexadecimalnum);
return 0;
}
For quotient = -50; the correct output should be:
ffffffce
But this function's output is:
.
With positive numbers the output is always correct but with negative numbers not.
I'm having a hard time understanding to why it doesn't work with negative numbers.
Some fixes:
unsigned int quotient - you need to convert -50 to a large hex number in two's complement or you'll get the wrong number of iterations (2) in the loop, instead of 8 as required.
Removal of "magic numbers": '0' + remainder and 'A' + remainder - 10.
Zero initialize hexadecimalnum becaues it needs to be null terminated before printing a string from there. Better yet, add the null termination explicitly.
Use for loops when possible.
Might as well store the characters from the back to front and save the extra call of reversing the string.
Result:
#include <stdio.h>
// 4 bytes*2 = 8 nibbles
#define HEX_STRLEN (sizeof(int)*2)
int main()
{
unsigned int remainder;
int i = 0;
char hex[100];
for(unsigned int q = -50; q!=0; q/=16)
{
remainder = q % 16;
if (remainder < 10)
hex[HEX_STRLEN-i-1] = '0' + remainder;
else
hex[HEX_STRLEN-i-1] = 'A' + remainder - 10;
i++;
}
hex[HEX_STRLEN] = '\0'; // explict null termination
printf("%s\n", hex);
}
(There's lots of improvements than can be made still, this is just to be considered as the first draft.)
You can use printf's format specifier "%08x", then you can print any number in their respective hexadecimal representation.
#include <stdio.h>
void num_to_hex(int a, char *ptr) { snprintf(ptr, 9, "%08x", a); }
int main() {
char hex[10] = {};
num_to_hex(-50, hex);
printf("%s\n", hex);
return 0;
}
Output:
ffffffce

C converting 20 digit string to number for IBAN validation

I am doing an IBAN validation in C. For this I have a char* which is something like '2012129431327715102998'.
Now I want to check the IBAN by taken the value modulo 97.
So I want to do 2012129431327715102998 % 97.
I have already tried to convert the char* with strtoull but this gives me an out-of-range error. So my question is: How can I convert this char* to a number where I can do a modulo calculation? Thanks in advance
You can write a custom function for this. Applying the modulo operator on partial sums, you can convert a number of arbitrary length:
#include <stdio.h>
int mod97(const char *s) {
int res = 0;
while (*s >= '0' && *s <= '9') {
res = (res * 10 + (*s++ - '0')) % 97;
}
return res;
}
int main(int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
printf("%s -> %d\n", argv[i], mod97(argv[i]));
}
return 0;
}
Output:
./mod97 2012129431327715102998
2012129431327715102998 -> 53
This method is simpler and more generic than the one described in the wiki article: computing the modulo 97 of a large number can be achieved by splitting the number in chunks of 9 digits and combining the modulo of these chunks. This splitting is specific to 97 and works because 1000000000 % 97 == 1. The above method works for any modulo value up to INT_MAX / 10.
A simple way without using additional library is to remember that mathematically: mod(a*b, c) == mod(b * mod(a, c), c). So you can process the number in chunks:
// suitable for a 32 bits system, can use 8 for a 64 bits one
#define NB 4
/*********************
* Initial is a string containin only digits representing an arbitrary large number
* div in a number < 10000 (because NB is 4)
* ******************/
int large_mod(char *initial, int div) {
char old[1 + (NB * 2)] = ""; // enough room for a remainder and next chunk
long val;
for (unsigned i=0; i<strlen(initial); i+= NB) {
strncat(old, initial + i, NB); // add the new chunk
val = atol(old) % div; // compute the remainder
sprintf(old, "%ld", val); // keep it for next chunk
// printf("%ld ", val); // uncomment for debugging
}
return (int) val;
}
For 2012129431327715102998 % 97, it gives as expected 53.

Writing IEEE 754-1985 double as ASCII on a limited 16 bytes string

This is a follow-up to my original post. But I'll repeat it for clarity:
As per DICOM standard, a type of floating point can be stored using a Value Representation of Decimal String. See Table 6.2-1. DICOM Value Representations:
Decimal String: A string of characters representing either a fixed
point number or a floating point number. A fixed point number shall
contain only the characters 0-9 with an optional leading "+" or "-"
and an optional "." to mark the decimal point. A floating point number
shall be conveyed as defined in ANSI X3.9, with an "E" or "e" to
indicate the start of the exponent. Decimal Strings may be padded with
leading or trailing spaces. Embedded spaces are not allowed.
"0"-"9", "+", "-", "E", "e", "." and the SPACE character of Default
Character Repertoire. 16 bytes maximum
The standard is saying that the textual representation is fixed point vs. floating point. The standard only refers to how the values are represented within in the DICOM data set itself. As such there is not requirement to load a fixed point textual representation into a fixed-point variable.
So now that this is clear that DICOM standard implicitely recommend double (IEEE 754-1985) for representing a Value Representation of type Decimal String (maximum of 16 significant digits). My question is how do I use the standard C I/O library to convert back this binary representation from memory into ASCII onto this limited sized string ?
From random source on internet, this is non-trivial, but a generally accepted solution is either:
printf("%1.16e\n", d); // Round-trippable double, always with an exponent
or
printf("%.17g\n", d); // Round-trippable double, shortest possible
Of course both expression are invalid in my case since they can produce output much longer than my limited maximum of 16 bytes. So what is the solution to minimizing the loss in precision when writing out an arbitrary double value to a limited 16 bytes string ?
Edit: if this is not clear, I am required to follow the standard. I cannot use hex/uuencode encoding.
Edit 2: I am running the comparison using travis-ci see: here
So far the suggested codes are:
Serge Ballesta
chux
Mark Dickinson
chux
Results I see over here are:
compute1.c leads to a total sum error of: 0.0095729050923877828
compute2.c leads to a total sum error of: 0.21764383725715469
compute3.c leads to a total sum error of: 4.050031792674619
compute4.c leads to a total sum error of: 0.001287056579548422
So compute4.c leads to the best possible precision (0.001287056579548422 < 4.050031792674619), but triple (x3) the overall execution time (only tested in debug mode using time command).
It is trickier than first thought.
Given the various corner cases, it seems best to try at a high precision and then work down as needed.
Any negative number prints the same as a positive number with 1 less precision due to the '-'.
'+' sign not needed at the beginning of the string nor after the 'e'.
'.' not needed.
Dangerous to use anything other than sprintf() to do the mathematical part given so many corner cases. Given various rounding modes, FLT_EVAL_METHOD, etc., leave the heavy coding to well established functions.
When an attempt is too long by more than 1 character, iterations can be saved. E.g. If an attempt, with precision 14, resulted with a width of 20, no need to try precision 13 and 12, just go to 11.
Scaling of the exponent due to the removal of the '.', must be done after sprintf() to 1) avoid injecting computational error 2) decrementing a double to below its minimum exponent.
Maximum relative error is less than 1 part in 2,000,000,000 as with -1.00000000049999e-200. Average relative error about 1 part in 50,000,000,000.
14 digit precision, the highest, occurs with numbers like 12345678901234e1 so start with 16-2 digits.
static size_t shrink(char *fp_buffer) {
int lead, expo;
long long mant;
int n0, n1;
int n = sscanf(fp_buffer, "%d.%n%lld%ne%d", &lead, &n0, &mant, &n1, &expo);
assert(n == 3);
return sprintf(fp_buffer, "%d%0*llde%d", lead, n1 - n0, mant,
expo - (n1 - n0));
}
int x16printf(char *dest, size_t width, double value) {
if (!isfinite(value)) return 1;
if (width < 5) return 2;
if (signbit(value)) {
value = -value;
strcpy(dest++, "-");
width--;
}
int precision = width - 2;
while (precision > 0) {
char buffer[width + 10];
// %.*e prints 1 digit, '.' and then `precision - 1` digits
snprintf(buffer, sizeof buffer, "%.*e", precision - 1, value);
size_t n = shrink(buffer);
if (n <= width) {
strcpy(dest, buffer);
return 0;
}
if (n > width + 1) precision -= n - width - 1;
else precision--;
}
return 3;
}
Test code
double rand_double(void) {
union {
double d;
unsigned char uc[sizeof(double)];
} u;
do {
for (size_t i = 0; i < sizeof(double); i++) {
u.uc[i] = rand();
}
} while (!isfinite(u.d));
return u.d;
}
void x16printf_test(double value) {
printf("%-27.*e", 17, value);
char buf[16+1];
buf[0] = 0;
int y = x16printf(buf, sizeof buf - 1, value);
printf(" %d\n", y);
printf("'%s'\n", buf);
}
int main(void) {
for (int i = 0; i < 10; i++)
x16printf_test(rand_double());
}
Output
-1.55736829786841915e+118 0
'-15573682979e108'
-3.06117209691283956e+125 0
'-30611720969e115'
8.05005611774356367e+175 0
'805005611774e164'
-1.06083057094522472e+132 0
'-10608305709e122'
3.39265065244054607e-209 0
'33926506524e-219'
-2.36818580315246204e-244 0
'-2368185803e-253'
7.91188576978592497e+301 0
'791188576979e290'
-1.40513111051994779e-53 0
'-14051311105e-63'
-1.37897140950449389e-14 0
'-13789714095e-24'
-2.15869805640288206e+125 0
'-21586980564e115'
For finite floating point values the printf() format specifier "%e" well matches
"A floating point number shall be ... with an "E" or "e" to indicate the start of the exponent"
[−]d.ddd...ddde±dd
The sign is present with negative numbers and likely -0.0. The exponent is at least 2 digits.
If we assume DBL_MAX < 1e1000, (safe for IEEE 754-1985 double), then the below works in all cases: 1 optional sign, 1 lead digit, '.', 8 digits, 'e', sign, up to 3 digits.
(Note: the "16 bytes maximum" does not seem to refer to C string null character termination. Adjust by 1 if needed.)
// Room for 16 printable characters.
char buf[16+1];
int n = snprintf(buf, sizeof buf, "%.*e", 8, x);
assert(n >= 0 && n < sizeof buf);
puts(buf);
But this reserves room for the optional sign and 2 to 3 exponent digits.
The trick is the boundary, due to rounding, of when a number uses 2 or uses 3 exponent digits is fuzzy. Even testing for negative numbers, the -0.0 is an issue.
[Edit] Also needed test for very small numbers.
Candidate:
// Room for 16 printable characters.
char buf[16+1];
assert(isfinite(x)); // for now, only address finite numbers
int precision = 8+1+1;
if (signbit(x)) precision--; // Or simply `if (x <= 0.0) precision--;`
if (fabs(x) >= 9.99999999e99) precision--; // some refinement possible here.
else if (fabs(x) <= 1.0e-99) precision--;
int n = snprintf(buf, sizeof buf, "%.*e", precision, x);
assert(n >= 0 && n < sizeof buf);
puts(buf);
Additional concerns:
Some compilers print at least 3 exponent digits.
The maximum number of decimal significant digits for IEEE 754-1985 double needed varies on definition of need, but likely about 15-17. Printf width specifier to maintain precision of floating-point value
Candidate 2: One time test for too long an output
// Room for N printable characters.
#define N 16
char buf[N+1];
assert(isfinite(x)); // for now, only address finite numbers
int precision = N - 2 - 4; // 1.xxxxxxxxxxe-dd
if (signbit(x)) precision--;
int n = snprintf(buf, sizeof buf, "%.*e", precision, x);
if (n >= sizeof buf) {
n = snprintf(buf, sizeof buf, "%.*e", precision - (n - sizeof buf) - 1, x);
}
assert(n >= 0 && n < sizeof buf);
puts(buf);
C library formatter has no direct format for your requirement. At a simple level, if you can accept the waste of characters of the standard %g format (e20 is written e+020: 2 chars wasted), you can:
generate the output for the %.17g format
if it is greater the 16 characters, compute the precision that would lead to 16
generate the output for that format.
Code could look like:
void encode(double f, char *buf) {
char line[40];
char format[8];
int prec;
int l;
l = sprintf(line, "%.17g", f);
if (l > 16) {
prec = 33 - strlen(line);
l = sprintf(line, "%.*g", prec, f);
while(l > 16) {
/* putc('.', stdout);*/
prec -=1;
l = sprintf(line, "%.*g", prec, f);
}
}
strcpy(buf, line);
}
If you really try to be optimal (meaning write e30 instead of e+030), you could try to use %1.16e format and post-process the output. Rationale (for positive numbers):
the %1.16e format allows you to separate the mantissa and the exponent (base 10)
if the exponenent is between size-2 (included) and size (excluded): just correctly round the mantissa to the int part and display it
if the exponent is between 0 and size-2 (both included): display the rounded mantissa with the dot correctly placed
if the exponent is between -1 and -3 (both included): start with a dot, add eventual 0 and fill with rounded mantissa
else use a e format with minimal size for the exponent part and fill with the rounded mantissa
Corner cases:
for negative numbers, put a starting - and add the display for the opposite number and size-1
rounding : if first rejected digit is >=5, increase preceding number and iterate if it was a 9. Process 9.9999999999... as a special case rounded to 10
Possible code:
void clean(char *mant) {
char *ix = mant + strlen(mant) - 1;
while(('0' == *ix) && (ix > mant)) {
*ix-- = '\0';
}
if ('.' == *ix) {
*ix = '\0';
}
}
int add1(char *buf, int n) {
if (n < 0) return 1;
if (buf[n] == '9') {
buf[n] = '0';
return add1(buf, n-1);
}
else {
buf[n] += 1;
}
return 0;
}
int doround(char *buf, unsigned int n) {
char c;
if (n >= strlen(buf)) return 0;
c = buf[n];
buf[n] = 0;
if ((c >= '5') && (c <= '9')) return add1(buf, n-1);
return 0;
}
int roundat(char *buf, unsigned int i, int iexp) {
if (doround(buf, i) != 0) {
iexp += 1;
switch(iexp) {
case -2:
strcpy(buf, ".01");
break;
case -1:
strcpy(buf, ".1");
break;
case 0:
strcpy(buf, "1.");
break;
case 1:
strcpy(buf, "10");
break;
case 2:
strcpy(buf, "100");
break;
default:
sprintf(buf, "1e%d", iexp);
}
return 1;
}
return 0;
}
void encode(double f, char *buf, int size) {
char line[40];
char *mant = line + 1;
int iexp, lexp, i;
char exp[6];
if (f < 0) {
f = -f;
size -= 1;
*buf++ = '-';
}
sprintf(line, "%1.16e", f);
if (line[0] == '-') {
f = -f;
size -= 1;
*buf++ = '-';
sprintf(line, "%1.16e", f);
}
*mant = line[0];
i = strcspn(mant, "eE");
mant[i] = '\0';
iexp = strtol(mant + i + 1, NULL, 10);
lexp = sprintf(exp, "e%d", iexp);
if ((iexp >= size) || (iexp < -3)) {
i = roundat(mant, size - 1 -lexp, iexp);
if(i == 1) {
strcpy(buf, mant);
return;
}
buf[0] = mant[0];
buf[1] = '.';
strncpy(buf + i + 2, mant + 1, size - 2 - lexp);
buf[size-lexp] = 0;
clean(buf);
strcat(buf, exp);
}
else if (iexp >= size - 2) {
roundat(mant, iexp + 1, iexp);
strcpy(buf, mant);
}
else if (iexp >= 0) {
i = roundat(mant, size - 1, iexp);
if (i == 1) {
strcpy(buf, mant);
return;
}
strncpy(buf, mant, iexp + 1);
buf[iexp + 1] = '.';
strncpy(buf + iexp + 2, mant + iexp + 1, size - iexp - 1);
buf[size] = 0;
clean(buf);
}
else {
int j;
i = roundat(mant, size + 1 + iexp, iexp);
if (i == 1) {
strcpy(buf, mant);
return;
}
buf[0] = '.';
for(j=0; j< -1 - iexp; j++) {
buf[j+1] = '0';
}
if ((i == 1) && (iexp != -1)) {
buf[-iexp] = '1';
buf++;
}
strncpy(buf - iexp, mant, size + 1 + iexp);
buf[size] = 0;
clean(buf);
}
}
I think your best option is to use printf("%.17g\n", d); to generate an initial answer and then trim it. The simplest way to trim it is to drop digits from the end of the mantissa until it fits. This actually works very well but will not minimize the error because you are truncating instead of rounding to nearest.
A better solution would be to examine the digits to be removed, treating them as an n-digit number between 0.0 and 1.0, so '49' would be 0.49. If their value is less than 0.5 then just remove them. If their value is greater than 0.50 then increment the printed value in its decimal form. That is, add one to the last digit, with wrap-around and carry as needed. Any trailing zeroes that are created should be trimmed.
The only time this becomes a problem is if the carry propagates all the way to the first digit and overflows it from 9 to zero. This might be impossible, but I don't know for sure. In this case (+9.99999e17) the answer would be +1e18, so as long as you have tests for that case you should be fine.
So, print the number, split it into sign/mantissa strings and an exponent integer, and string manipulate them to get your result.
Printing in decimal cannot work because for some numbers a 17 digit mantissa is needed which uses up all of your space without printing the exponent. To be more precise, printing a double in decimal sometimes requires more than 16 characters to guarantee accurate round-tripping.
Instead you should print the underlying binary representation using hexadecimal. This will use exactly 16 bytes, assuming that a null-terminator isn't needed.
If you want to print the results using fewer than 16 bytes then you can basically uuencode it. That is, use more than 16 digits so that you can squeeze more bits into each digit. If you use 64 different characters (six bits) then a 64-bit double can be printed in eleven characters. Not very readable, but tradeoffs must be made.

Any decent way of printing out floats and doubles with commas?

I'm working on a program that regards with currency. Ive been finding a solution to display money values decently like this:
9,999.99 USD
Remember when assigning a certain variable with a value (money), you musn't insert commas.
I.e.:
double money=9999.99;
And when accessing it;
printf("%.2l USD",money);
Which will output:
9999.99 USD
This is not what I want, especially on bigger amounts exceeding the hundredth, thousandth, millionth, or even billionth place value.
Now I can't find any solution than printing out the desired output directly on the printf.
printf("9,999.99");
Which is undesirable with many variables.
Can anyone help me out?
Please take a look and printf manual page taking note of the following bit:
*"For some numeric conversions a radix character ("decimal point") or thousands' grouping character is used. The actual character used depends on the LC_NUMERIC part of the locale. The POSIX locale uses '.' as radix character, and does not have a grouping character. Thus,
printf("%'.2f", 1234567.89);
results in "1234567.89" in the POSIX locale, in "1234567,89" in the nl_NL locale, and in "1.234.567,89" in the da_DK locale."*
This can be changed by the function setlocale
There is a function, strfmon which might be able to help you
First, don't use floating-point types to represent money because normally floating-point types are binary and as such cannot represent all decimal fractions (cents) exactly, further these types are prone to rounding errors. Use integers instead and count cents instead of dollars.
#include <stdio.h>
#include <limits.h>
unsigned long long ConstructMoney(unsigned long long dollars, unsigned cents)
{
return dollars * 100 + cents;
}
void PrintWithCommas(unsigned long long n)
{
char s[sizeof n * CHAR_BIT + 1];
char *p = s + sizeof s;
unsigned count = 0;
*--p = '\0';
do
{
*--p = '0' + n % 10;
n /= 10;
if (++count == 3 && n)
{
*--p = ',';
count = 0;
}
} while (n);
printf("%s", p);
}
void PrintMoney(unsigned long long n)
{
PrintWithCommas(n / 100);
putchar('.');
n %= 100;
putchar('0' + n / 10);
putchar('0' + n % 10);
}
int main(void)
{
PrintMoney(ConstructMoney(0, 0)); puts("");
PrintMoney(ConstructMoney(0, 1)); puts("");
PrintMoney(ConstructMoney(1, 0)); puts("");
PrintMoney(ConstructMoney(1, 23)); puts("");
PrintMoney(ConstructMoney(12, 34)); puts("");
PrintMoney(ConstructMoney(123, 45)); puts("");
PrintMoney(ConstructMoney(1234, 56)); puts("");
PrintMoney(ConstructMoney(12345, 67)); puts("");
PrintMoney(ConstructMoney(123456, 78)); puts("");
PrintMoney(ConstructMoney(1234567, 89)); puts("");
return 0;
}
Output (ideone):
0.00
0.01
1.00
1.23
12.34
123.45
1,234.56
12,345.67
123,456.78
1,234,567.89
If you're using the standard library, there's no way to do this -- you have to write some code that does it by hand.
I would recommend multiplying the value by 100, casting to integer, and printing the digits with separators as needed -- it's much easier to handle individual digits on an integer.
The following code, for instance, will fill a char * buffer with the string representation of the value you have:
void formatString (double number, char * buffer) {
if (number < 0) {
*buffer = '-';
formatString(number, buffer + 1);
return;
}
unsigned long long num = (unsigned long long) (number * 100);
unsigned long long x; // temporary storage for counting the digits
unsigned char digits;
for (x = num / 1000, digits = 1; x; digits ++, x /= 10);
// counts the digits, also ensures that there's at least one digit
unsigned char pos; // digit position
for (pos = 1, x = 100; pos < digits; pos ++, x *= 10);
// reuses x as a value for extracting the digit in the needed position;
char * current = buffer;
for (pos = digits; pos; pos --) {
*(current ++) = 48 + (num / x);
// remember 48 + digit gives the ASCII for the digit
if (((pos % 3) == 1) && (pos > 1)) *(current ++) = ',';
num %= x;
x /= 10;
}
*(current ++) = '.';
*(current ++) = 48 + num / 10;
*(current ++) = 48 + num % 10;
*current = 0;
}

Converting from decimal to binary number system using strings

I need help trying to fix the second part of my program, converting decimal to binary, this is what I have so far and when i compile it i keep getting 0 so im not sure what i did wrong. any help please?
#include <stdio.h>
#include <string.h>
#include <math.h>
int main()
{
char string[100];
int s;
char a;
char j;
int sum = 0;
int r;
int q;
printf("B = B to D\n");
printf("D = D to B\n");
printf("choose which one to convert to:");
scanf("%c%c", &a, &j);
if (a == 'B')
{
printf("enter binary number to convert to decimal: ");
scanf("%s", string);
for(s = strlen(string)-1; s >= 0; s--)
{
if(string[s] == '1')
{
sum = sum + pow(2, strlen(string) - (s +1));
}
}
printf("the decimal number is: %d\n", sum);
}
if (a == 'D')
{
printf("enter decimal number to convert to binary: ");
scanf("%s", string);
while (r > 0)
{
r = q%2;
q = q%2;
}
printf("the binary number is: %d\n", r);
}
return 0;
}
There are a few problems here. For one thing, the first time that you check r, it is uninitialized. Another problem is that you're setting both r and q to the same value every time you go through the while loop. You probably want q = q/2 instead of q = q%2. Finally, you're overwriting r every pass through the loop, instead of building up a string of bits. Here's some pseudocode for what you want to do:
output_string = ""
while input > 0:
output_string = concat(input%2, output_string)
input /= 2
print output_string
Note that you're also never converting the string you read in to an integer and putting that in q, so you'll need to do that as well.
This C99 code will do the trick if you want a negative number to be printed as a string of binary digits with a sign:
if (a == 'D')
{
int r;
printf("enter decimal number to convert to binary: ");
scanf("%d", &r);
int i = 0;
int p = (r >= 0) ? (r = -r, 1) : 0;
string[i++] = '\0';
do
{
string[i++] = (r % 2) == 0 ? '0' : '1';
r /= 2;
} while (r != 0);
if (!p)
string[i++] = '-';
int k = 0;
while (--i > k)
{
char t = string[i];
string[i] = string[k];
string[k++] = t;
}
printf("the binary number is: %s\n", string);
}
For example, given -1234 (decimal), the output is -10011010010 (binary). It also handles both the extremes: INT_MAX, -INT_MAX and INT_MIN (assuming 32-bit int):
B = B to D
D = D to B
choose which one to convert to: D
enter decimal number to convert to binary: 2147483647
the binary number is: 1111111111111111111111111111111
B = B to D
D = D to B
choose which one to convert to: D
enter decimal number to convert to binary: -2147483647
the binary number is: -1111111111111111111111111111111
B = B to D
D = D to B
choose which one to convert to: D
enter decimal number to convert to binary: -2147483648
the binary number is: -10000000000000000000000000000000
If, on the other hand, you want the bit pattern corresponding to the value, then Joachim Pileborg's answer does that for you.
(It's C99 code because it declares variables at convenient points part way through a block, rather than at the start of a block as C89 requires.)
The simplest thing is probably to convert the string input to a proper integer (using e.g. strtol), and the convert that number to a string containing only ones and zeroes.
Something like:
/* Convert a (possibly signed) decimal number in a string to a long integer */
unsigned long number = (unsigned long) strtol(string, NULL, 10);
char output_string[65]; /* If longs are 64 bits, plus one for terminator */
char *output_ptr = output_string;
/* Start with the highest bit, go down to the lowest */
/* sizeof(long) is either 4 or 8 depending on 32 or 64 bit platforms */
/* Multiply with 8 to get the number of bits */
/* -1 because bits are numbered from 0 to 31 (or 63) */
for (int bit = (sizeof(unsigned long) * 8) - 1; bit >= 0; bit--)
{
/* Using right shift to get the current bit into the lowest position */
/* Doing bitwise AND to see if the lowest bit is a one or a zero */
/* Adding '0' makes a a printable ASCII value of a digit */
*output_ptr++ = ((number >> bit) & 1) + '0';
/* `*output_ptr` gets the value that `output_ptr` points to */
/* Then use the `++` operator to increase the pointer */
/* Now `output_ptr` points to the next character in `output_string` */
}
/* Terminate string */
*output_ptr = '\0';
printf("%ld in binary is %s\n", number, output_string);

Resources