I'm new to C and I need to write a function in c which converts an integer to a string in the specified base and print it.
If I were given an input value of 1234 (base 10) it should return 2322 (base 8).
Here is the code structure I'm currently working on:
void int2ascii(int value, int base){
int a=0;
if (value > base) {
a = a + int2char(value); //recursive case
int2ascii(value/base, base); //base case
}
printf("%s\n",a);
}
The program won't run, can someone enlighten me?
Thanks
Analysis of your program
I noted first off that a is declared int, but it was being passed to printf with %s as the format specifier. %s designates the associated argument will be a string, which a is not. The result will be undefined behavior, and is a possible cause for your crash.
You do not specify what int2char() does, but let's assume that it converts a numeric "digit" into a corresponding char value. With that in mind, let us suppose its implementation is similar to:
int int2char(int d) {
return "0123456789abcdefghijklmnopqrstuvwxyz"[d];
}
In your code, you pass value to int2char(). In my hypothetical implementation, this would cause out-of-bounds access of the array, and thus undefined behavior. This is indicates a logic error, and another possible cause for your crash.
I note that if value is less than base, a remains 0. Probably, you really mean to compute a value for a even when value is less than base. This indicates another logic error.
Base conversion
The number dKdK-1 .. d0, where each di is in (0 .. 9), is a short form for ∑di×10i. To discover the base 10 digits of a number N, the process is:
di = ⌊N / 10i⌋ mod 10
But, as it turns out, you can replace 10 with some other base number to compute the digits for a number in that base:
di = ⌊N / Bi⌋ mod B
In your code, the recursive call that divides by the base represents the first part of the calculation. However, in your calculation of a, you were missing the "mod" part of the calculation.
Solution 1
Assuming base is from 2 to 36, and that your int2char(d) does something more or less as illustrated earlier:
void int2ascii(int value, int base){
int a=0;
a = a + int2char(value%base);
if (value > base) {
int2ascii(value/base, base);
}
printf("%c",a);
}
Because you are not passing a into your recursive call, you can only use it to store the current digit to be printed. So, move the code to store the value in a out of the if check, since you always want a sensible value to print at the end. The digit in a is in the radix base, so you need the modulus result to get the right digit value. Since a represents a character, change the format string to match, and remove the \n so that all the digits end up on the same line.
Solution 2
The first solution is an attempt to leave most of your original code intact. Since a is initialized to 0, the extra addition does not make it incorrect. But, since the print doesn't happen until the very end, the value doesn't really need to be stored at all, and can be calculated at the point you actually want to print it. With that in mind, the program can be simplified to:
void int2ascii(int value, int base){
if (value > base) {
int2ascii(value/base, base);
}
printf("%c",int2char(value%base));
}
#include <stdio.h>
#include <limits.h>
char *int2ascii_aux(int n, int base, char *s){
//base {x| 2 <= x <= 36 }
static const char *table = "0123456789abcdefghijklmnopqrstuvwxyz";
if(n){
*--s = table[n % base];
return int2ascii_aux(n/base, base, s);
} else {
return s;
}
}
char *int2ascii(int n, int base){
//base {x| 2<= x <= 36 }
static char s[sizeof(int)*CHAR_BIT+1];
if(n <= 0){
*s = '0';
return s;
}
if(base < 2 || base > 36){
*s = '\0';
return s;
}
return int2ascii_aux(n, base, s + sizeof(s) -1);
}
int main(){
printf("%s\n", int2ascii(1234, 8));
return 0;
}
Related
I'm currently working on a project that recreates the printf function in C, however, I'm having trouble implementing my code while I use recursion.
Note that I'm only allowed to use the write function, and one of the functions that I'm working on and having issues is the one that I have to print a pointer.
This is my function for printing the address:
int ft_print_address(long unsigned int nb)
{
int counter;
if (nb == 0)
return(write(1, "(nil)", 5));
else
{
counter = write(1, "0x", 2);
counter += print_hex(nb);
return (counter);
}
}
static int print_hex(long unsigned int nb)
{
int counter;
char *hex;
counter = 0;
hex = "0123456789abcdef";
if (nb > 9)
{
print_hex(nb / 16);
}
counter += write(1, &hex[nb % 16], 1);
return (counter);
}
the variable (counter) which is the return value of the number of characters written, is always 1, even if number of characters written is superior. The recursion is working because it's printing the address in hexadecimal just like the printf function, but the counter never increases.
Can someone help me?
I take it that write(1, c, 1) will print exactly one character and return 1. It's my best guess.
You are not taking into account the number of characters printed by the recursive call. If nb is, say, 0x1234, then it will have print_hex(0x1234 / 16) print 3 characters, and then it will print the 4.
Your condition for callin print_hex recursively is also wrong. A hex number will have more than one digit if it is larger than 15, not 9.
I also take this is homework, so I won't write the code down. But these two changes should be enough.
I've got an assignment where I have to sum whole numbers up to 100 digits.
They gave me this struct to represent big numbers (I think there are better ways to represent this, but I'm not allowed to modify it):
typedef struct {
char* string;
int lengthError;
} BigNumber;
Where string is the number itself and lengthError is the length of the number or an error that is a previously defined enum.
I've also have the implementation of the sum function
BigNumber *sum(BigNumber* num1, BigNumber* num2) {
BigNumber* result = malloc(sizeof(BigNumber));
int limit = getLength(num1->lengthError, num2->lengthError);
result->string = malloc(limit);
int digitResult;
int index = limit -1;
int carry = 0;
while(index != -1) {
int d1 = ((int)num1->string[index]) - ((int)'0');
int d2 = ((int)num2->string[index]) - ((int)'0');
digitResult = d1 + d2 + carry;
if (digitResult > 9) {
digitResult = digitResult - 10;
carry = 1;
} else {
carry = 0;
}
itoa(digitResult, &result->string[index], 10); //I think this is the problem
index--;
}
result->string[limit] = '\0';
printf("result: %s\n", result->string);
return result;
}
I haven't finished writing that function, I know there are a lot of flaws in it, but the problem is that I can't get to sum 12 + 12. The result I get is 2.
I thought approaching this problem by picking the lasts character of both numbers, transform them into an int and sum them having in mind the carry digit. After I got the result in digitResult I try to convert it to a char and store it in the corresponding position of the result->string pointer
Once it has finished the operation, I add an \0 at the last position of the result->string.
So the question is, how do I make this operation to work as desired? Debugging the code, I noticed that the first time it stores the first result in result->string, following the example above this would be a number 4, it stores trash in that position instead. In the second addition, I store a number 2 correctly and that's the final result I get in when I print the result.
Your use of the itoa function is a problem (though, as you have also suggested, maybe not the only one).
The itoa function converts its first argument into a null-terminated string - so, as well as writing the character representation of digitResult at the indicated place in the string, it also adds a '\0' character after it. Thus, your string will always be terminated immediately after the last digit you write, and 12 + 12, giving 24 will appear to be just the first character: 2.
What you can do instead is to convert the digit yourself (reversing the operation you used to get the d1 and d2 values), then just directly set the string element to the converted digit.
So, instead of:
itoa(digitResult, &result->string[index], 10);
use:
result->string[index] = (char)(digitResult + '0');
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
int main()
{
int i,a,n,r;
n=12345;
r=0;
for(i=4;i>=0;i--)
{
a=n%10;
n=n/10;
r=r+a*pow(10,i);
}
printf("%d",r);
return 0;
}
Current output - 54320
Expected output - 54321
Please advise on what I may change in my code to reflect the correct output.
The pow function returns a value of type double. Because this is a floating point type, the result it returns will not always be exact.
What's happening in this case is that on the last iteration of the loop pow(10, 0) returns a value slightly less than 1. This results in the right hand side of r=r+a*pow(10,i); to similarly be slightly less than 54321. When this value is then assigned to r, which is of type int, it gets truncated.
Rather than using the pow function here, use the following:
r=r*10+a;
This shifts the current digits in r over by 1, then adds the newest digit to the end. Also, rather than using a for loop, use while (n>0) instead. Then it doesn't matter how many digits you have.
while (n>0)
{
a=n%10;
n=n/10;
r=r*10+a;
}
Here is a simplified version of your algorithm:
void reverse_digits(int a) {
int b = 0;
while (a > 0) {
b = b * 10 + a % 10;
a /= 10;
}
printf("%d\n", b);
}
As for converting to character arrays as mentioned in the comments it's worth to notice that the convertion function will do similar arithmetic operations in order to convert the integer to character array, so doing the reversing using integers seems more convenient.
I am trying to make a C program for converting a given number in say base x, to base y. I chose to narrow it down upto base 20 (i.e. Base 2 to 20). When it comes to scanning a hexadecimal number (includes ABCDEF too, right?) for example, I am stuck. Please look at my program below:
/* NOTE: This program uses two step approach to convert a given number in any base (except base 10, in which case we will use only "toany()") to any other base*/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
int inum,ibase, obase;
int todec(); //function to convert to decimal from any base
int toany(int); //function to convert from decimal to any base
int exp(int,int); //used in other function
void main()
{
int num,choice;
char strr[100];
enum{A=10,B,C,D,E,F,G,H,I,J};
here:
printf("Enter the base (RADIX) of your number: ");
scanf("%d",&ibase);
printf("Enter the number in base %d: ",ibase);
scanf("%s",strr);
printf("Enter the base in which you want the output: ");
scanf("%d",&obase);
inum=atoi(strr);
switch(obase)
{
case 10:
num=todec();
printf("Output in base 10: %d\n",num);
break;
default:
if(ibase==10)
num=toany(inum);
else
num=toany(todec());
printf("Output in base %d: %d\n",obase,num);
break;
}
printf("WANNA DO IT AGAIN? If yes, Press 1 else press 0:");
scanf("%d",&choice);
if(choice==1)
goto here;
else
exit(0);
getch();
}
int exp(int p, int q)
{
int i,result=1;
for(i=1;i<=q;i++)
{
result=result*p;
}
return(result);
}
int todec()
{
int inumarr[100],dupnum=inum,i=0,counter,decnum=0;
while(dupnum!=0)
{
inumarr[i]=dupnum%10;
dupnum/=10;
i++;
}
for(counter=0;counter<i;counter++)
{
decnum=decnum+inumarr[counter]*exp(ibase, counter);
}
return(decnum);
}
int toany(int num)
{
int outnumarr[100],i=0,q,result=0;
while(num!=0)
{
outnumarr[i]=num%obase;
num=num/obase;
i++;
}
for(q=0;q<i;q++)
{
result=result+outnumarr[q]*exp(10,q);
}
return(result);
}
Thanks for reading! Now, I know it's definitely a mess where I tried to scan as a string and then applied atoi function on a string that might contain alphabets (like "19E" in base 16...which is 414 in base 10). So, I am looking for a decent solution which will allow the user of this program to enter any number like "19E" and my program will interpret that 'E' as 14 (AS DEFINED IN MY ENUM) and also a decent way to show an output of numbers like "19E" would be great.
Disclaimer: The code I've put into this answer is untested. I'm currently on a mobile device, so even compiling it is less convenient than usual. I will strive to include enough details for you to find your way past any (possible) errors, please point them out though... On another day I'll polish this post off by adding more checks (described at the end) and explain serialisation as well as deserialisation. As it stands, however, it seems you're just asking about deserialisation, so without further adeau:
Build a lookup table of some description containing each character from your base. For characters then you can (usually) get away with using string operations. For example:
unsigned char hex_digit[] = "00112233445566778899AaBbCcDdEeFf";
If you use strchr and some pointer arithmetic you can now find the offset of a character, divide by two to reduce it to a value within 0 .. 15, or modulo by two to discriminate between lowercase and uppercase.
You can devise any base like this, with a generic loop parsing the input to facilitate larger values...
size_t to_native_uimax(char *str, unsigned char *base, uintmax_t *value) {
size_t x, base_size = strlen(str);
uintmax_t v = 0;
for (x = 0; str[x]; x++) {
unsigned char *c = strchr(base, str[x]);
if (!c) break;
v *= base_size / 2;
v += (c - base) / 2;
}
*value = v;
return x;
}
Signage is a bit trickier to handle, but because we only need to handle the sign at the start of the string we can reuse the code above.
size_t to_native_imax(unsigned char *str, unsigned char *base, intmax_t *value) {
uintmax_t v = 0;
size_t x = to_native_uimax(str + !!strchr("-+", *str), base, &v);
*value = *str == '-' ? -(intmax_t)v : v;
return x;
}
Also note that this code isn't strictly portable; if it's possible that this might be deployed to a system that has negative zeros or signals on overflow more checks should precede the (intmax_t) conversion.
n.b. I know that this question has been asked on StackOverflow before in a variety of different ways and circumstances, but the search for the answer I seek doesn't quite help my specific case. So while this initially looks like a duplicate of a question such as How can I convert an integer to a hexadecimal string in C? the answers given, are accurate, but not useful to me.
My question is how to convert a decimal integer, into a hexadecimal string, manually. I know there are some beat tricks with stdlib.h and printf, but this is a college task, and I need to do it manually (professor's orders). We are however, permitted to seek help.
Using the good old "divide by 16 and converting the remainder to hex and reverse the values" method of obtaining the hex string, but there must be a big bug in my code as it is not giving me back, for example "BC" for the decimal value "188".
It is assumed that the algorithm will NEVER need to find hex values for decimals larger than 256 (or FF). While the passing of parameters may not be optimal or desirable, it's what we've been told to use (although I am allowed to modify the getHexValue function, since I wrote that one myself).
This is what I have so far:
/* Function to get the hex character for a decimal (value) between
* 0 and 16. Invalid values are returned as -1.
*/
char getHexValue(int value)
{
if (value < 0) return -1;
if (value > 16) return -1;
if (value <= 9) return (char)value;
value -= 10;
return (char)('A' + value);
}
/* Function asciiToHexadecimal() converts a given character (inputChar) to
* its hexadecimal (base 16) equivalent, stored as a string of
* hexadecimal digits in hexString. This function will be used in menu
* option 1.
*/
void asciiToHexadecimal(char inputChar, char *hexString)
{
int i = 0;
int remainders[2];
int result = (int)inputChar;
while (result) {
remainders[i++] = result % 16;
result /= (int)16;
}
int j = 0;
for (i = 2; i >= 0; --i) {
char c = getHexValue(remainders[i]);
*(hexString + (j++)) = c;
}
}
The char *hexString is the pointer to the string of characters which I need to output to the screen (eventually). The char inputChar parameter that I need to convert to hex (which is why I never need to convert values over 256).
If there is a better way to do this, which still uses the void asciiToHexadecimal(char inputChar, char *hexString) function, I am all ears, other than that, my debugging seems to indicate the values are ok, but the output comes out like \377 instead of the expected hexadecimal alphanumeric representation.
Sorry if there are any terminology or other problems with the question itself (or with the code), I am still very new to the world of C.
Update:
It just occurred to me that it might be relevant to post the way I am displaying the value in case its the printing, and not the conversion which is faulty. Here it is:
char* binaryString = (char*) malloc(8);
char* hexString = (char*) malloc(2);
asciiToBinary(*(asciiString + i), binaryString);
asciiToHexadecimal(*(asciiString + i), hexString);
printf("%6c%13s%9s\n", *(asciiString + i), binaryString, hexString);
(Everything in this code snip-pit works except for hexString)
char getHexValue(int value)
{
if (value < 0) return -1;
if (value > 16) return -1;
if (value <= 9) return (char)value;
value -= 10;
return (char)('A' + value);
}
You might wish to print out the characters you get from calling this routine for every value you're interested in. :) (printf(3) format %c.)
When you call getHexValue() with a number between 0 and 9, you return a number between 0 and 9, in the ASCII control-character range. When you call getHexValue() with a number between 10 and 15, you return a number between 65 and 75, in the ASCII letter range.
The sermon? Unit testing can save you hours of time if you write the tests about the same time you write the code.
Some people love writing the tests first. While I've never had the discipline to stick to this approach for long, knowing that you have to write tests will force you to write code that is easier to test. And code that is easier to test is less coupled (or 'more decoupled'), which usually leads to fewer bugs!
Write tests early and often. :)
Update: After you included your output code, I had to comment on this too :)
char* binaryString = (char*) malloc(8);
char* hexString = (char*) malloc(2);
asciiToBinary(*(asciiString + i), binaryString);
asciiToHexadecimal(*(asciiString + i), hexString);
printf("%6c%13s%9s\n", *(asciiString + i), binaryString, hexString);
hexString has been allocated one byte too small to be a C-string -- you forgot to leave room for the ASCII NUL '\0' character. If you were printing hexString by the %c format specifier, or building a larger string by using memcpy(3), it might be fine, but your printf() call is treating hexString as a string.
In general, when you see a
char *foo = malloc(N);
call, be afraid -- the C idiom is
char *foo = malloc(N+1);
That +1 is your signal to others (and yourself, in two months) that you've left space for the NUL. If you hide that +1 in another calculation, you're missing an opportunity to memorize a pattern that can catch these bugs every time you read code. (Honestly, I found one of these through this exact pattern on SO just two days ago. :)
Is the target purely hexadecimal, or shall the function be parametizable. If it's constrained to hex, why not exploit the fact, that a single hex digit encodes exactly four bits?
This is how I'd do it:
#include <stdlib.h>
#include <limits.h> /* implementation's CHAR_BIT */
#define INT_HEXSTRING_LENGTH (sizeof(int)*CHAR_BIT/4)
/* We define this helper array in case we run on an architecture
with some crude, discontinous charset -- THEY EXIST! */
static char const HEXDIGITS[0x10] =
{'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
void int_to_hexstring(int value, char result[INT_HEXSTRING_LENGTH+1])
{
int i;
result[INT_HEXSTRING_LENGTH] = '\0';
for(i=INT_HEXSTRING_LENGTH-1; value; i--, value >>= 4) {
int d = value & 0xf;
result[i] = HEXDIGITS[d];
}
for(;i>=0;i--){ result[i] = '0'; }
}
int main(int argc, char *argv[])
{
char buf[INT_HEXSTRING_LENGTH+1];
if(argc < 2)
return -1;
int_to_hexstring(atoi(argv[1]), buf);
puts(buf);
putchar('\n');
return 0;
}
I made a librairy to make Hexadecimal / Decimal conversion without the use of stdio.h. Very simple to use :
char* dechex (int dec);
This will use calloc() to to return a pointer to an hexadecimal string, this way the quantity of memory used is optimized, so don't forget to use free()
Here the link on github : https://github.com/kevmuret/libhex/
You're very close - make the following two small changes and it will be working well enough for you to finish it off:
(1) change:
if (value <= 9) return (char)value;
to:
if (value <= 9) return '0' + value;
(you need to convert the 0..9 value to a char, not just cast it).
(2) change:
void asciiToHexadecimal(char inputChar, char *hexString)
to:
void asciiToHexadecimal(unsigned char inputChar, char *hexString)
(inputChar was being treated as signed, which gave undesirable results with %).
A couple of tips:
have getHexValue return '?' rather than -1 for invalid input (make debugging easier)
write a test harness for debugging, e.g.
int main(void)
{
char hexString[256];
asciiToHexadecimal(166, hexString);
printf("hexString = %s = %#x %#x %#x ...\n", hexString, hexString[0], hexString[1], hexString[2]);
return 0;
}
#include<stdio.h>
char* inttohex(int);
main()
{
int i;
char *c;
printf("Enter the no.\n");
scanf("%d",&i);
c=inttohex(i);
printf("c=%s",c);
}
char* inttohex(int i)
{
int l1,l2,j=0,n;
static char a[100],t;
while(i!=0)
{
l1=i%16;
if(l1>10)
{
a[j]=l1-10+'A';
}
else
sprintf(a+j,"%d",l1);
i=i/16;
j++;
}
n=strlen(a);
for(i=0;i<n/2;i++)
{
t=a[i];
a[i]=a[n-i-1];
a[n-i-1]=t;
}
//printf("string:%s",a);
return a;
//
}
In complement of the other good answers....
If the numbers represented by these hexadecimal or decimal character strings are huge (e.g. hundreds of digits), they won't fit in a long long (or whatever largest integral type your C implementation is providing). Then you'll need bignums. I would suggest not coding your own implementation (it is tricky to make an efficient one), but use an existing one like GMPlib