views:

3299

answers:

7

Hi,

I am trying to convert an integer number in C into an array containing each of that number's digits

i.e. if I have

int number = 5400

how can I get to

int numberArray[4]

where

numberArray[0] = 0;
numberArray[1] = 0;
numberArray[2] = 4;
numberArray[3] = 5;

Any suggestions gratefully received

--dave

+2  A: 

Hint: Take a look at this earlier question "Sum of digits in C#". It explains how to extract the digits in the number using several methods, some relevant in C.

From Greg Hewgill's answer:

/* count number of digits */
int c = 0; /* digit position */
int n = number;

while (n != 0)
{
    n /= 10;
    c++;
}

int numberArray[c];

c = 0;    
n = number;

/* extract each digit */
while (n != 0)
{
    numberArray[c] = n % 10;
    n /= 10;
    c++;
}
Zach Scrivena
A: 

Figuring out the number of digits is tricky, but assuming it's always 4 digits you can do:

for (i = 0; i < 4; i++) {
  numberArray[i] = number%10;
  number = number div 10;
}
Mark Pim
In C, it's called /, not div.
David Hanak
No, numbers of digits is easy. Just use log10(a) + 1.
vava
in some cases, surely this would evaluate to the incorrect value ? e.g. log10(50)+1 = 2.70 = 3 as an integer.
droseman
its not going to be always 4 digits - its an incremental counter
droseman
It's always would work by definition of logarithm. But you have to floor() result as conversion to (int) does.
vava
Just to make myself clear, logarithm is increasing function, so if x < y then log(x) < log(y) and vice versa. Then log10(100) == log10(10 ** 2) is 2 and log10(10) is 1. So if 10 < x < 100 then 1 < log(x) < 2 hence the formula.
vava
I see, looking up the definition of floor() made it completely clear
droseman
+8  A: 

This would work for numbers >= 0

#include <math.h>

char * convertNumberIntoArray(unsigned int number) {
    int length = (int)floor(log10((float)number)) + 1;
    char * arr = new char[length];
    int i = 0;
    do {
     arr[i] = number % 10;
     number /= 10;
     i++;
    } while (number != 0);
    return arr;
}

EDIT: Just a little bit more C style but more cryptic.

#include <math.h>

char * convertNumberIntoArray(unsigned int number) {
    unsigned int length = (int)(log10((float)number)) + 1;
    char * arr = (char *) malloc(length * sizeof(char)), * curr = arr;
    do {
     *curr++ = number % 10;
     number /= 10;
    } while (number != 0);
    return arr;
}
vava
why is this function a char pointer ? And what does new char[length] do? It looks like a pointer to the first index of the array, but my compiler doesn't seem to like 'new char'
droseman
'new char' is C++speak. The proper way to do it in C is the second bit of code.
Chris Lutz
Also, it's important that, at the end of your program, you call `free()` on whatever array you got back from this function. Otherwise you leak memory.
Chris Lutz
Shouldn't this be returning int *?
Nick Presta
It might but there's no reason to use 4 byte int to store 4 bit digit. Char is just more compact way to do that, although it could easily be substituted to ints.
vava
A: 

C code:

/* one decimal digit takes a few more than 3 bits. (2^3=8, 2^4=16) */
int digits[(sizeof (int) * CHAR_BIT) / 3 + 1], 
    *digitsp = digits;
do {
    *digitsp++ = number % 10;
    number /= 10;
} while(number > 0);

You will see how many digits you converted by taking the difference

digitsp - digits

If you want to put it into a function:

#define MIN_DIGITS_IN_INT ((sizeof (int) * CHAR_BIT) / 3 + 1)

int to_array(int number, int *digits) {
    int *digitsp = digits;
    do {
        *digitsp++ = number % 10;
        number /= 10;
    } while(number > 0);
    return digitsp - digits;
}

int main() {
    int number = rand();
    int digits[MIN_DIGITS_IN_INT];
    int n = to_array(number, digits);

    /* test whether we're right */
    while(n-- > 0) 
        printf("%d", digits[n]);
    }
    printf(" = %d\n", number);
}

I prefer automatic arrays to dynamic memory allocation in this case, since it's easier to do it right and not leak accidentally.

Johannes Schaub - litb
"A bit more than 3 bits?" I think you just won some kind of phrasing prize.
unwind
yeah, i figure it sounds strange oO let me change it
Johannes Schaub - litb
Awesome how different logic path produces the same results :) 32 / 3 + 1 is almost the same as log10(2 ** 32) + 1 == log2(2 ** 32) / log2(10) + 1 == 32 / log2(10) + 1 < 32 / 3 + 1
vava
can u explain MIN_DIGITS_IN_INT ((sizeof (int) * CHAR_BIT) / 3 + 1) ?
yesraaj
rajKumar, it needs to be a compile time constant. so i didn't use log10. you need 3.32193 bits to store one decimal place (ld(10)) - ten binary decisions. that means, that you cannot store more than (sizeof (int) * CHAR_BIT)/3.32193 places in an int, which is 9.63296
Johannes Schaub - litb
(here). round up (INT_MAX does not really use all places fully - it's not 9999999999) it's 10 which is also actually the amount of digits in an INT_MAX. well, actually that calcs the places in an unsigned int. but those are always at least as many as places for an int. so that works indeed :)
Johannes Schaub - litb
+1  A: 

If you need to take negative numbers into account, you might need some extra logic. In fact, when playing around with arrays you don't know the size of upfront, you may want to do some more safety checking, and adding an API for handling the structure of the data is quite handy too.

// returns the number of digits converted
// stores the digits in reverse order (smalles digit first)
// precondition: outputdigits is big enough to store all digits.
//
int convert( int number, int* outputdigits, int* signdigit ) {

  int* workingdigits = outputdigits;

  int sign = 1;
  if( number < 0 ) { *signdigit = -1; number *= -1; }
  ++workingdigits;

  for ( ; number > 0; ++ workingdigits ) {
    *workingdigits = number % 10;
    number = number / 10;
  }

  return workingdigits - outputdigits;
}

void printdigits( int* digits, int size, int signdigit ) {
  if( signdigit < 0 ) printf( "-" );

  for( int* digit = digits+size-1; digit >= digits; --digit ){
    printf( "%d", *digit );
  }
}

int main() {
   int digits[10];
   int signdigit;
   printdigits( digits, convert( 10, digits, &signdigit ), signdigit );
   printdigits( digits, convert( -10, digits, &signdigit ), signdigit );
   printdigits( digits, convert( 1005, digits, &signdigit ), signdigit );

}
xtofl
no negative numbers required, fortunately. Its an upcounting hours counter. It is possible that this number could get quite large, though.
droseman
+2  A: 

You could calculate the number of digits in an integer with logarithm rather than a loop. Thus,

int * toArray(int number)
{
    int n = log10(number) + 1;
    int i;
    int *numberArray = calloc(n, sizeof(int));
    for ( i = 0; i < n; ++i, number /= 10 )
    {
        numberArray[i] = number % 10;
    }
    return numberArray;
}
Christoffer
+1 This looks good to me
Mark Pim
A: 

using vadim's code, I came up with this test program:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

char * convertNumberIntoArray(unsigned int number) {
    unsigned int length = (int)(log10((float)number)) + 1;
    char * arr = (char *) malloc(length * sizeof(char)), * curr = arr;
    do {
        *curr++ = number % 10;
        number /= 10;
    } while (number != 0);
    return arr;
}



int main(void)
{
    int InputNumber;
    int arr[5];

    printf("enter number: \n");
    scanf("%d", &InputNumber);

    convertNumberIntoArray(InputNumber);

    printf("The number components are: %d %d %d\n", arr[0],arr[1],arr[2]);

    system("PAUSE");    
    return 0;
}

but the output is garbage. Can anyone advise if I have done something stupid here?

/***** output *****/
enter number:
501
The number components are: 2009291924 2009145456 -1
Press any key to continue . . .

--dave

droseman
The function returns an array. You need this: `char *arr; arr = convertNumberIntoArray(InputNumber);` Note that `arr` should be a `char *`, not an `int []`. If you want it to be an `int *`, you should change the function to return `int *`, not `char *`.
Chris Lutz
thanks Chris, it now works
droseman
don't forget to free(arr) after you are done with it. Alternatively, you can use @litb approach and create static array with length (32/3 + 1) == 11 and just fill it in then.
vava