I have a 40 digit hex number stored in a string, I have to store it inside a struct called Int40 that only contains a pointer to an int.
typedef struct Int40
{
// a dynamically allocated array to hold a 40
// digit integer, stored in reverse order
int *digits;
} Int40;
this is what I have tried
Int40 *parseString(char *str)
{
Int40 *value = malloc(sizeof(Int40) * MAX40);
for (int i = 0; i < MAX40; i++)
{
value[i] = (int)str[i];
}
return value;
}
int main()
{
Int40 *p;
p = parseString("0123456789abcdef0123456789abcdef01234567");
printf("-> %d\n", *p);
}
I know that an Int cant contain 40 digits thats why I tried to store each number from the string in an array of integers but my code doesnt seem to work.
Edit: Also the number contains letters because is a hex number, will I have to the get the ascii value of the hex number to be able to store it in the array of int, how do i do that?
You might do something like the following (note that I omit verification of the argument char* and also assume that hex characters are lowercase)
// with if statements:
Int40 *parseString(char *str)
{
Int40 *value = malloc(sizeof(Int40) * MAX40);
// save the digits array locally (same memory address as value)
int* digits = value->digits;
for (int i = 0; i < MAX40; i++)
{
char c = str[i];
// decimal digits case
if (c >= '0' && c <= '9') {
digits[i] = c - '0'; // subtract '0' to get the numberical value of c
} else { // hex case
digits[i] = (c - 'a') + 10; // subtract 'a' to get the numerical value of c as 0 + 10 for hex characters A - F
}
}
return value;
}
An alternative:
// with a switch statements:
Int40 *parseString(char *str)
{
Int40 *value = malloc(sizeof(Int40) * MAX40);
// save the digits array locally (same memory address as value)
int* digits = value->digits;
for (int i = 0; i < MAX40; i++)
{
char c = str[i];
switch (c) {
// hex 10 - 15
case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f':
digits[i] = (c - 'a') + 10;
break;
// hex 0 - 9
default:
digits[i] = c - '0';
}
}
return value;
}
#include <stdio.h>
#include <stdlib.h>
typedef int* hex;
hex parseString(char *str)
{
hex value = (hex)malloc(sizeof(int)*40);
for (int i = 0; i < 40; i++)
{
value[i] = str[i];
}
return value;
}
int main()
{
hex p;
p = parseString("0123456789abcdef0123456789abcdef01234567");
printf("-> %d\n", p[0]);
}
...
#include <stdio.h>
#include <stdlib.h>
typedef struct Int40
{
int* hex;
}Int40;
Int40 parseString(char *str)
{
Int40 value;
value.hex = (int*)malloc(sizeof(int)*40);
for (int i = 0; i < 40; i++)
{
value.hex[i] = str[i];
}
return value;
}
int main()
{
Int40 p;
p = parseString("0123456789abcdef0123456789abcdef01234567");
printf("-> %d\n", p.hex[0]);
}
Related
I have to make a program in which I have to add the result of x dices with n faces plus or minus a constant(C). The input should be a string like this: "xDn+-C" (x, n and C must be a decimal number). For example: "4D5+6" or "6D9-5". The D just means "Dice".
I used a function to randomize the rolls but I don't know how to continue...
void initD6(void) {
srand((unsigned)time( NULL ) );
}
int D6(void) {
return ((rand()%6)+1);
}
int main(){
char Dice[4];
for(i=0; i<5; i++){
Dice[i] = D6();
return 0;
}
I don't know how should I take that input as a string and the adding or substracting, and also don't know what should I do next.
Add a struct:
struct rules
{
int dices;
int facesPerDice;
int offset;
};
Solve the dice problem:
int throwDice(int faces)
{
return (rand() % faces) + 1;
}
int playGame(struct rules rules)
{
int result = 0;
for (int i = 0; i < rules.dices; i++)
result += throwDice(rules.facesPerDice);
return result + rules.offset;
}
Solve the parsing problem:
/**
Converts a string to a unsigned int until an invalid character is found or a null character is found.
You should replace this with the function you normally use to convert a string to a integer.
*/
unsigned int stringToUInt(char *str)
{
unsigned int result = 0;
int charindex = 0;
char currentchar;
while ((currentchar = str[charindex++]) != '\0')
{
if (currentchar < '0' || currentchar > '9')
break;
result *= 10;
result += currentchar - '0';
}
return result;
}
/**
Reads a string and generates a struct rules based on it.
The string is expected to be given in the following format:
[uint]'D'[uint]['+' or '-'][uint]
where:
the first uint is the number of dices to roll
the second uint is the number of faces per dice
the third uint is the offset
Terminates the program if something goes wrong.
*/
struct rules parse(char *str)
{
struct rules result;
result.dices = stringToUInt(str);
while (*(str++) != 'D')
if (*str == '\0')
exit(1);
result.facesPerDice = stringToUInt(str);
while (*(str++) != '+' && *(str-1) != '-')
if (*str == '\0')
exit(1);
result.offset = stringToUInt(str);
result.offset *= (*(str-1) == '+' ? 1 : -1);
return result;
}
Put everything together:
int main(int argc, char *argv[])
{
srand(time(NULL));
char input[] = "3D6+9"; //You could use console input if you want
struct rules rules = parse(input);
int gameResult = playGame(rules);
printf("Game result: %d\n", gameResult);
return 0;
}
Assuming no errors in the input, a function which solves your task is:
int throw_dice(const char* s)
{
int num, sides, res;
sscanf(s,"%iD%i%i", &num, &sides, &res);
for (int i = 0; i < num; ++i) {
res += rand() % sides + 1;
}
return res;
}
For simple string parsing sscanf() is a pretty good function. For more complex tasks it's better to use a regular expression library.
As usual, don't relay on rand() for anything but the most simple dice games, with no money involved.
You can try it with the following full example:
#include <stdio.h>
int throw_dice(const char* s)
{
int num, sides, res;
sscanf(s,"%iD%i%i", &num, &sides, &res);
for (int i = 0; i < num; ++i) {
res += rand() % sides + 1;
}
return res;
}
void throw_multiple_times(const char* s, int times)
{
printf("%s: ", s);
for (int i = 0; i < times; ++i) {
printf("%i ", throw_dice(s));
}
printf("\n");
}
int main(void)
{
srand((unsigned)time(NULL));
const char* s;
throw_multiple_times("4D5+6", 100);
throw_multiple_times("6D9-5", 100);
return 0;
}
Test it here.
Write a C function, that accepts a null-terminated string, containing a hexadecimal string, and returns the integer value. You cannot call any C library function, except strlen() to code the function. The decimal string will only contain 0-4 ASCII characters from ‘0’ through ‘9’ and ‘A’ through ‘F’. No error handling is required. If the string is empty, then return a value of 0.
I've constantly tried fixing my errors, but once I fix them, new errors pop up, resulting in me being confused.
#include <stdlib.h> /*used for EXIT_SUCCESS */
#include <stdio.h> /*used for printf */
#include <string.h> /* used for strlen */
#include <stdbool.h> /* used for bool */
#include <math.h>
unsigned int hexStringTouint(const char str[], int length, int n[])
{
int i, j;
int intvalue = 0;
int digit;
for(i = (length-1), j = 0; i --, j++)
{
if(n[i]>='0' && n[i] <='9')
{
digit = n[i] - 0x30;
}
else if(n[i]>= 'A' && n[i] <= 'F')
{
switch(n[i])
{
case 'A': digit = 10; break;
case 'B': digit = 11; break;
case 'C': digit = 12; break;
case 'D': digit = 13; break;
case 'E': digit = 14; break;
case 'F': digit = 15; break;
}
}
intvalue += digit*pow(16,j);
}
printf("int value is %d\n", intvalue);
return 0;
}
int main(void)
{
int i, length, intvalue;
unsigned char n[] = "";
printf("Enter your hexadecimal string: ");
scanf("%c\n", n);
intvalue = 0;
length = strlen(n);
return EXIT_SUCCESS;
}
I am getting error messages saying
expected ';' in 'for' statement specifier
and how const char* converts between pointers and integers.
Much of OP's code is the right track, yet various coding errors exist.
Add test condition
// for(i = (length-1), j = 0; i --, j++)
// v
for(i = (length-1), j = 0; i >= 0; i --, j++)
cannot call any C library function, except strlen()
// intvalue += digit*pow(16,j);
intvalue += digit*(1u << (4*j));
Return the value
Requirement "... and returns the integer value"
//int intvalue = 0;
//...
//printf("int value is %d\n", intvalue);
//return 0;
unsigned intvalue = 0;
...
printf("integer value is %u\n", intvalue);
return intvalue;
Buffer too small
// unsigned char n[] = "";
// scanf("%c\n", n);
char n[100] = "";
scanf("%99s", n);
hexStringTouint()
Function not called in main().
Other issues exist
A simpler approach
unsigned hexStringTouint2(const char *str) {
unsigned value = 0;
while (*str) {
unsigned digit = hexCharTouint(*str); // tbd code
value = value*16 + digit;
str++;
}
return value;
}
I have an unsigned char array which contains hex bytes like below:
unsigned char array[255];
array[0] = 'F';
array[1] = 'F';
array[2] = 'E';
array[3] = '2';
array[4] = 'A';
array[5] = 'A';
array[6] = 'C';
array[7] = 'C';
I want to merge them so that it becomes:
array[0] = "FF"
array[1] = "E2"
array[2] = "AA"
array[3] = "CC"
array[0] = '\xFF';
array[1] = '\xE2';
array[2] = '\xAA';
array[3] = '\xCC';
I have tried using sprintf but then I do not know how to specify index number in it. Any help.?
So, you want to convert your string, made of hexadecimal characters, into an array of bytes, right? Know your data.
sprintf() will not help you, since it produces strings. Instead, you will need to extract the 'value' of each hexa character and use it to calculate the value of your bytes.
So, let's create a helper function to convert a hexadecimal character to its integer value (or -1 if it is invalid). We will use the characters' ASCII values and the fact that character ranges are contiguous in the ASCII table
int char2hexa(unsigned char c)
{
if(c >= '0' && c <= '9') {
return (c - '0'); /* will return 0-9 */
} else if(c >= 'A' && c <= 'F') {
return (c - 'A') + 10; /* will return 10-15 */
} else if(c >= 'a' && c <= 'f') {
return (c - 'a') + 10; /* will return 10-15 */
} else {
return -1;
}
}
Now a byte will be constructed from two hexa values by using one as the upper nibble (multiplied by 16 or shifted left by 4) and the other as a lower nibble, so let's have a function for that:
unsigned char hexvals2byte(int upper, int lower)
{
return (upper * 16 + lower);
}
and put the pieces together. I will assume that:
you know the length of your input data
the length is even (you need two characters per byte)
you want to put the result in the same array
Here comes.
#include <stdio.h>
#include <stdlib.h>
unsigned char array[255];
array[0] = 'F';
array[1] = 'F';
array[2] = 'E';
array[3] = '2';
array[4] = 'A';
array[5] = 'A';
array[6] = 'C';
array[7] = 'C';
unsigned length = 8;
int upper, lower;
for(int i = 0; i < length; i+=2) {
upper = char2hexa(array[i]);
lower = char2hexa(array[i+1]);
if(upper < 0 || lower < 0) {
/* handle input data format error */
fprintf(stderr, "ERROR: Cannot decode hexa values '%c%c'\n", array[i], array[i+1]);
exit(EXIT_FAILURE);
}
array[i/2] = hexvals2byte(upper, lower);
}
So you need a result array of unsigned char result[128][3], then assign the part results, grouping 2 source elements into one result sub-element:
unsigned char result[128][3] = { 0 };
int i;
for (i = 0; i < 255; ++i)
{
result[i/2][i%2] = array[i];
}
The reason for size 3 is, that you need 2 characters and one zero-delimiter to form a string.
An easy way to convert a digit to number is to subtract '0' from it:
char digit = '3';
int number = digit - '0'; /* number = 3 */
This works only for digits (digit >= '0' && digit <= '9'), for hexadecimal digits ('A', 'B', etc.) you have to do a little more job:
unsigned char result[127];
int i;
unsigned char current;
unsigned char calc_diff(unsigned char digit) {
if(digit >= '0' && digit <= '9')
return '0';
else if(digit >= 'A' && digit <= 'F')
return 'A' - 10;
else if(digit >= 'a' && digit <= 'f')
return 'a' - 10;
else
return 0; // handle invalid digit
}
for(i = 0; i < 128; ++i) {
current = array[2 * i];
result[i] = (current - calc_diff(current)) << 4;
current = array[(2 * i) + 1];
result[i] |= current - calc_diff(current);
}
You want to convert characters to their hexadecimal value and combine them in pairs.
Here is a simple program to illustrate how you can do this:
#include <stdio.h>
#include <string.h>
static int xdigit(unsigned char c) {
/* this method is inefficient but works for all encodings */
static const char xdigits[] = "abcdef0123456789ABCDEF";
const char *p = memchr(xdigits, c, 22);
return p ? (p - xdigits + 10) & 15 : -1;
}
int main(void) {
unsigned char array[255];
while (scanf("%254s", array) == 1) {
int i, j, d, d2 = 0;
for (i = j = 0; array[i] != '\0'; i++) {
d = xdigit(array[i]);
if (d < 0) {
printf("invalid hexadecimal digit: %c\n", array[i]);
break;
}
d2 = (d2 << 4) | d;
if (i & 1) {
array[j++] = (unsigned char)d2;
d2 = 0;
}
}
array[j] = '\0';
printf("converted array: %s\n", array);
}
return 0;
}
Here is a more elaborate version, with an separate conversion function and more explicit output:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
static int xdigit(unsigned char c) {
switch (c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
return c - '0';
case 'A': case 'a':
return 10;
case 'B': case 'b':
return 11;
case 'C': case 'c':
return 12;
case 'D': case 'd':
return 13;
case 'E': case 'e':
return 14;
case 'F': case 'f':
return 15;
default:
return -1;
}
}
int xconvert(unsigned char *dest, const unsigned char *src, int len) {
int i, j, d, d2 = 0;
for (i = j = 0; i < len; i++) {
d = xdigit(src[i]);
if (d < 0) {
printf("invalid hexadecimal digit: %c\n", src[i]);
return -1;
}
d2 = (d2 << 4) | d;
if (i & 1) {
dest[j++] = (unsigned char)d2;
d2 = 0;
}
}
if (i & 1) {
printf("missing trailing digit\n");
return -1;
}
return j;
}
int main(void) {
unsigned char array[255];
int i, len, c;
while (scanf("%254s", array) == 1) {
len = xconvert(array, array, strlen((char *)array));
if (len >= 0) {
printf("converted array: \"");
for (i = 0; i < len; i++) {
c = array[i];
if (isprint(c)) {
putchar(c);
} else {
printf("\\x%02X", c);
}
}
printf("\"\n");
}
}
return 0;
}
my stab at it. Here you have to know the size of the array. in your case 255
//counters and array's
int first = 0;
int second = 0;
int count = 0;
char foo[8] = {'F', 'F', 'E', '2', 'A', 'A', 'C', 'C'};
//array half the size of the first one.
char *done[4];
//loop through first array
while (first <= 7)
{
//if its the first letter
if (second == 0)
{
//allocate enough mem to second arr
done[count] = (char *)malloc(sizeof(char *) * 3);
//assaign the first letter
done[count][0] = foo[first];
//indicate the next step for the second letter
second = 1;
}
//if its the second letter
else if (second == 1)
{
//assign second letter
done[count][1] = foo[first];
//null the string
done[count][2] = '\0';
//increase posistion index for the second arr
count++;
//indicate nexxt step is a the first letter of the next step
second = 0;
}
//increment the index for the first arr
first++;
}
Given that the data is in ASCII format and you want to merge it into a raw binary format, then:
for(size_t i=0; i<n; i++)
{
array[i] = to_int(array[i]);
}
where to_int() is your custom routine for converting from hexadecimal ASCII to integer. That is, if digit subtract with '0', else if upper-case letter subtract with 'A' and add 0xA.
Then after that, merge the items:
for(size_t i=0; i<n; i+=2)
{
array[i] = (unsigned int)array[i]<<4 | array[i+1];
}
I suppose you mix up an 8 bit value (e.g. 0x0F, which is 15 in decimal) with a character value like 'F' (which corresponds to 70 in ASCII format) with a string literal "FF" (which corresponds to a pointer to a sequence of the three character values {'F','F','\0'}.
From the context you present it seems that you mean 8 bit values, which are represented by data type unsigned char.
Given that, the code could look as follows:
unsigned char array[255] = { 0xF,0xE,0x2,0xA,0xA,0xC,0xC };
int target=0;
for (int i=0; i<254; i+=2) {
array[target] = (array[i] << 4) + array[i+1];
target++;
}
Maybe there are uncertain things but perhaps you want to do this.
#include <stdio.h>
int main(void){
unsigned char array[255] = {//or char -> hex byte
'\xF', '\xF', '\xE', '\x2',
'\xA', '\xA', '\xC', '\xC',
};
int len = 8;
for(int i = 0, j = 0; i < len; i += 2){
array[j++] = (array[i] << 4) | array[i+1];
}
len = len / 2;
for(int i = 0; i < len; i++){
printf("%02hhX", array[i]);//FFE2AACC
}
printf("\n");
}
When the data held first is a hex character
#include <stdio.h>
#include <ctype.h>
int main(void){
unsigned char array[255] = {
'F', 'F', 'E', '2',
'A', 'A', 'C', 'C',
};
int len = 8;
for(int i = 0, j = 0; i < len; i++){
if(isxdigit(array[i])){//maybe redundant
if(isdigit(array[i])){
array[i] -= '0';
} else {
array[i] -= isupper(array[i]) ? 'A' : 'a';
array[i] += 10;
}
} else {
fprintf(stderr, "invalid data %c\n", array[i]);
return -1;
}
}
for(int i = 0, j = 0; i < len; i += 2){
array[j++] = (array[i] << 4) | array[i+1];
}
len = len / 2;
for(int i = 0; i < len; i++){
printf("%02hhX", array[i]);
}
printf("\n");
}
I have a program that takes a char array and calls the function convert. The function determines whether the character is a letter or number. The program is supposed to output the first letter it finds in the string. and the first numbers it finds in the string. My loop to stop looking for letters after it finds one isn't working.
Any thoughts?
Code is written in C using the Borland Compiler.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int convert (char array[],char **);
int main()
{
int intval;
char array[512], *charptr;
printf("Input a string that starts with a series of decimal digits:\n>");
while ( gets( array ) != NULL ){
intval = convert(array, &charptr );
printf ("Intval contains %d, Charptr contains '%s'\n", intval, charptr);
}
system("pause");
return 0;
}
int convert (char array[],char ** charptr)
{
int i, x, c = 0;
char b[512];
for (i=0;i<strlen(array);i++){
if (isalpha(array[i]))
{
if(c >= 1){
*charptr = &array[i];
c++;
}
else
break;
}
else if ( isdigit(array[i]))
x = 10*x + array[i] - '0';
}
return x;
}
UPDATE:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int convert (char array[],char ** charptr);
int main()
{
int intval;
char array[512], *charptr;
printf("Input a string that starts with a series of decimal digits:\n>");
while ( gets( array ) != NULL ){
intval = convert(array, &charptr );
printf ("Intval contains %d, Charptr contains '%s'\n", intval, charptr);
}
system("pause");
return 0;
}
int convert (char array[],char ** charptr)
{
int i, x, c;
char b[512];
for (i=0;array[i] != 0;i++){
if ( isdigit(array[i]))
x = 10*x + array[i] - '0';
else if (isalpha(array[i]))
{
c++;
if(c >= 1){
*charptr = &array[i];
}
}
}
return x;
}
You have a logic error. c is initialized to 0. There is a line to increment c but it is inside an if block that will never be true.
if(c >= 1){
*charptr = &array[i];
c++;
}
Catch 22???
Perhaps you meant to use:
int convert (char array[],char ** charptr)
{
int i, x, c = 0;
char b[512];
for (i=0;i<strlen(array);i++){
if (isalpha(array[i]))
{
// No need for checking the value of c
// return as soon you find an alphabet.
*charptr = &array[i];
break;
}
else if ( isdigit(array[i]))
// If you are looking for an alphabet only,
// why do you have this block of code???
x = 10*x + array[i] - '0';
}
return x;
}
Update
Perhaps, this is what you are looking for.
int convert (char array[], char ** charptr)
{
size_t i;
int x = 0;
size_t len = strlen(array);
// Set charptr to NULL in case there are no letters in the input.
*charptr = NULL;
for (i=0;i<len;i++){
if ( isalpha(array[i]))
{
*charptr = &array[i];
return x;
}
else if ( isdigit(array[i]))
{
x = 10*x + array[i] - '0';
}
}
return x;
}
int scanString(char array[],char * charptr)
{
int len = strlen(array);
int digs = 0;
int x = 0;
*charptr = 0;
for (int i=0;i<len;i++){
if (charptr == 0 && isalpha(array[i]))
{
*charptr = array[i];
}
else if (digs == 0 && isdigit(array[i])){
x = array[i] - '0';
digs = 1;
}
if(digs > 0 && charptr != 0)
break;
}
return x;
}
the spec says return the first character found so changed the charptr.
I would need to figure out a way to do the following in standard C. Assume we are given a string representing a hexadecimal number with say n digits. We want to convert this to a string representing the same number in decimal. The strings could have an arbitrary number of digits. What's at least easy to deduce is that the decimal string needs <= 2n letters.
Once we reach the size limit for numbers that the machine can handle, then the length of the string becomes quite irrelevant, so a hexadecimal number with 100 digits should be just as easy/hard to convert as one with 1000 digits i.e. the same algorithm should work on both as it has to work in chunks.
Has anyone here thought about this? What's really annoying is that large powers of 2 have nonzero digits down to the first order, so any element in the hexadecimal sequence can affect the last digit in decimal...
I could only find questions where someone wanted a string converted to a number or a number to a string in some base. If someone wonders why I would need this. I'm playing around with arbitrary precision numbers and the most economical format for storing numbers in is base 256, so I need to print numbers given in this form (or equivalently any hexadecimal).
EDIT: So I implemented a conversion function and I'll share it here if anyone else might ever need it. This was very quick an dirty and a better implementation would of course start by replacing the digits buffer in the struct by something that gets dynamically allocated. Since all arithmetic happens in the "add" function it would then be easy to realloc this buffer to something bigger if an addition overflows. The output buffer size is always simple to assign, since any hexadecimal number converts to a decimal number with less or equal to twice the digits.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 1000
struct number {
unsigned char digits[MAXLEN];
unsigned int num_digits;
};
int add(struct number *, struct number *, struct number *);
int mult(struct number *, struct number *, struct number *);
int power(struct number *, unsigned int, struct number *);
void print_number(struct number *, char *);
void dec(struct number *);
void hex2dec(char *hex, char *outbuf)
{
int n;
char *s;
struct number decrep;
struct number twopow;
struct number digit;
decrep.num_digits = 0;
n = strlen(hex);
s = hex;
while(--n > -1) {
/* weight of digit */
twopow.num_digits = 2;
twopow.digits[0] = 6;
twopow.digits[1] = 1;
power(&twopow, n, &twopow);
/* Extract digit */
if(*s <= '9' && *s >= '0') {
digit.digits[0] = *s - '0';
digit.num_digits = 1;
} else if(*s <= 'f' && *s >= 'a') {
digit.digits[0] = *s - 'a';
digit.digits[1] = 1;
digit.num_digits = 2;
} else if(*s <= 'F' && *s >= 'A') {
digit.digits[0] = *s - 'A';
digit.digits[1] = 1;
digit.num_digits = 2;
}
s++;
mult(&digit, &twopow, &digit);
add(&decrep, &digit, &decrep);
}
/* Convert decimal number to a string */
if(decrep.num_digits == 0) {
*outbuf = '0';
*(++outbuf) = '\0';
return;
}
for(n = decrep.num_digits-1; n >= 0; n--) {
*(outbuf++) = '0' + decrep.digits[n];
}
*outbuf = '\0';
}
int main(void)
{
char buf[1000];
hex2dec("FFEa4334234FABCD", buf);
printf("%s", buf);
return 0;
}
void copy_number(struct number *dst, struct number *src)
{
int i;
for(i = 0; i < src->num_digits; i++) dst->digits[i] = src->digits[i];
dst->num_digits = src->num_digits;
}
int power(struct number *a, unsigned int n, struct number *b)
{
struct number atmp;
/* Are we exponentiating by 0? */
if(n == 0) {
b->num_digits = 1;
b->digits[0] = 1;
return 0;
}
copy_number(&atmp, a);
while(--n > 0) {
mult(&atmp, a, &atmp);
}
copy_number(b, &atmp);
return 0;
}
int mult(struct number *a, struct number *b, struct number *c)
{
struct number btmp;
struct number ctmp;
struct number *t;
/* Are we multiplying by 0? */
if(a->num_digits == 0 || b->num_digits == 0) {
c->num_digits = 0;
return 0;
}
if(a->num_digits < b->num_digits) {
t = a;
a = b;
b = t;
}
copy_number(&btmp, b);
copy_number(&ctmp, a);
while(1) {
/* Are we multiplying by 1? */
if(btmp.num_digits == 1 && btmp.digits[0] == 1) {
break;
}
add(&ctmp, a, &ctmp);
dec(&btmp);
}
copy_number(c, &ctmp);
return 0;
}
int add(struct number *a, struct number *b, struct number *c)
{
int i, j;
int carry;
struct number *t;
if(a->num_digits < b->num_digits) {
t = a;
a = b;
b = t;
}
for(i = 0, carry = 0; i < a->num_digits; i++) {
if(i >= b->num_digits) j = a->digits[i]+carry;
else j = a->digits[i]+b->digits[i]+carry;
if(j > 9) {
j -= 10;
carry = 1;
} else {
carry = 0;
}
c->digits[i]=j;
}
/* Did we overflow? */
if(carry > 0 && i == MAXLEN) return -1;
/* Carry over from last addition? */
if(carry > 0) {
c->digits[i] = carry;
c->num_digits = a->num_digits+1;
} else {
c->num_digits = a->num_digits;
}
return 0;
}
void print_number(struct number *a, char *buf)
{
int i;
if(a->num_digits == 0) {
printf("0");
return;
}
for(i = a->num_digits-1; i >= 0; i--) {
*(buf++) = '0' + a->digits[i];
}
*buf = '\0';
}
void dec(struct number *a)
{
int i;
for(i = 0; i < a->num_digits; i++) {
if(a->digits[i] > 0) {
a->digits[i]--;
break;
}
a->digits[i] = 9;
}
/* Did number of digits get lower */
if(i == a->num_digits -1 && a->digits[i] == 0) {
for(i = a->num_digits - 1; i >= 0; i--) {
if(a->digits[i] != 0) {
a->num_digits = i + 1;
break;
}
}
}
}
Please note there is a bug in this code. As soon as the HEX string contains a 0 !
this snippet :
/* Extract digit */
if(*s <= '9' && *s >= '0') {
digit.digits[0] = *s - '0';
digit.num_digits = 1;
} else if(*s <= 'f' && *s >= 'a') {
gives digits[0] = 0; num_digites = 1;
But later in the mult() function there is the snipet :
if(a->num_digits == 0 || b->num_digits == 0) {
c->num_digits = 0;
return 0;
}
that test 0 by num_digits == 0. So I suggest to replace in the first function the snippet with :
if(*s == '0') {
digit.digits[0] = *s - '0';
digit.num_digits = 0;
}else if(*s <= '9' && *s > '0') {
digit.digits[0] = *s - '0';
digit.num_digits = 1;
} else if(*s <= 'f' && *s >= 'a') {
looks to work fine for me.
You can compare the result on this site : http://www.statman.info/conversions/hexadecimal.php