Convert char array to integer equivalent and vice-versa - c

I am trying to build a simple function to handle block striping onto a "fake" disk (implemented in memory as a nested array of n blocks of x bytes represented by 4 byte ints, stored to a regular file on close). Data is passed into my write_block function as an array of chars from the buffer in my open-file table (OFT).
In order to do this my thought process is to convert my array of chars to an integer value in blocks of 4 chars (the logic being 4x1 byte chars is equivalent to 1x4 byte integer) by using the following function:
//write_block(index, block_pointer)
// write block, start with array of characters and write integers to ldisk (convBlock == converted Block)
// return: 1 if successful, -1 if not
int write_block(int blockIndex, char *convBlock) {
if (strlen(convBlock) > blockSize) {
printf("Block passed to write exceeds max block size\n");
return -1;
}
int i, j;
int scalar, currIndex;
for (i = 0; i < strlen(convBlock) / sizeof(int) + ((strlen(convBlock) % sizeof(int) == 0) ? 0 : 1); i++) {
scalar = 1;
for (j = 0; j < sizeof(int); j++) {
currIndex = (i * sizeof(int) + j);
if (currIndex > strlen(convBlock))
break;
ldisk[blockIndex][i] += convBlock[i] * scalar;
scalar *= 1000;
}
}
return 1;
}
However, this doesn't work because the maximum size of an unsigned 4 bit integer is 4294967295 (10 digits), while converting a char array this way results in 12 digits (3 per char). I know I should technically be able to do this since a char takes up a single byte, while an integer takes 4.
My next thought was to convert to binary then convert back to an integer. However, I would need to somehow store the binary representation of 4 chars back to back which would require an integer with 4*8 = 32 digits, while the max size of the largest numeric type (long long) is 18446744073709551615 (20 digits).

My understanding of your goal is you want to store a null terminated block of characters to a virtual disk made of integers into block blockIndex.
Here is a simplified version of your function that can handle different storage types: 4 byte ints or 8 byte ints:
#include <stdint.h>
//write_block(index, block_pointer)
// write block, start with array of characters src and write integers to ldisk
// return: 1 if successful, -1 if not
int write_block(int blockIndex, const char *src) {
size_t i, j, k, size;
size = strlen(src) + 1; // include the null terminator in the written conversion.
if (size > blockSize) {
printf("Block passed to write exceeds current block size\n");
return -1;
}
for (i = j = k = 0; i < size; i++) {
ldisk[blockIndex][j] &= ~(0xFFULL << k);
ldisk[blockIndex][j] |= (unsigned long long)(unsigned char)src[i] << k;
k += 8;
if (k == sizeof(ldisk[blockIndex][j]) * 8) {
j++;
k = 0;
}
}
return 1;
}
Notes:
I included the null terminator in the conversion so the reading code knows where to stop.
The char values must be cast as unsigned char to avoid sign propagation in case char type is signed, which is the default on many systems.
You should return the number if blocks written (j) to the caller. This is useful information, and can easily be distinguished from -1 for errors.
This code does assume that char has 8 bits. Using CHAR_BITS instead of 8 would allow for other values with some other constant adjustments, if you really seek full compatibility with exotic platforms.
I use unsigned long long arithmetic to allow for the storage unit to be as large as possible.

Related

Weird behaviour of function with malloc() and realloc() resulting in Segmentation Fault

I have a function named num_to_binary, which is used to convert a decimal number stored in the form of array. The prototype for this function num_to_binary is as below:
void num_to_binary(int *number_b, int size_of_number);
Here:
number_b is pointer to array which stores my number. For example, if I would like to convert the number 12345 to binary, then I will be storing 12345 in number_b as follows:
number_b[0] = 1
number_b[1] = 2
number_b[2] = 3
number_b[3] = 4
number_b[4] = 5
Also, size_of_number is the number of digits in the number (or it is the number of elements in the array number_b). So for the number 12345, size_of_number has the value 5.
Below is the full declaration of the function num_to_binary:
void num_to_binary(int *number_b, int size_of_number)
{
int *tmp_pointer = malloc(1 * sizeof(int));
int curr_size = 1;
int i = 0;
while(!is_zero(number_b,size_of_number))
{
if(i != 0)
{
curr_size += 1;
tmp_pointer = realloc(tmp_pointer, curr_size * sizeof(int));
}
if(number_b[size_of_number - 1] % 2 == 1)
{
tmp_pointer[i] = 1;
divide_by_2(number_b,size_of_number);
i = i + 1;
}
else
{
tmp_pointer[i] = 0;
divide_by_2(number_b,size_of_number);
i = i + 1;
}
}
int *fin_ans;
fin_ans = malloc(curr_size * sizeof(int));
for(int j = 0 ; j < curr_size; j++)
{
fin_ans[curr_size-1-j] = tmp_pointer[j];
}
}
In the above function:
tmp_pointer: It is initially allocated some memory using malloc(), and is used to store the reverse of the binary representation of the number stored in number_b
curr_size: It stores the current size of tmp_pointer. It is initially set to 1.
i: It is used to keep track of the while loop. It is also used to reallocation purpose, which I have explained a bit later.
is_zero(number_b, size_of_number): It is a function, which returns 1 if the number stored in number_b is 0, else it returns 1.
divide_by_2(number_b, size_of_number): It divides the number stored in number_b by 2. It does NOT change the size of the array number_b.
fin_ans: It is an integer pointer. Since the binary representation stored in the array tmp_pointer will be the reverse of the actual binary representation of the number, so fin_ans will store the correct binary representation of number by reversing the content of tmp_pointer.
Below is the how this function works :
First of all, tmp_pointer is allocated a memory equal to the
size of 1 int. So, now tmp_pointer can store an integer.
We now go into the while loop. The loop will terminate only
when the number stored in number_b equals 0.
Now, we check if i is equal to 0 or not. If it is not equal to
zero, then this means than the loops has been run atleast once, and
in order to store the next binary digit, we resize the memory
allocated to tmp_pointer so that it can store the next bit.
If the last digit of the number is odd, then that implies that the
corresponding binary digit will be 1, else it will be 0. The
if and else condition do this task. They also increment
i each time one of them is executed, and also divide the number by 2.
Now, we are out of the loop. It's time to reverse the binary number
stored in tmp_pointer to get the final answer.
For this, we create a new pointer called fin_ans, and allocate
it the memory which will be used for storing the correct binary
representation of the number.
The last for loop is used to reverse the binary representation
and store the correct binary representation in fin_ans.
The problem:
The code runs for small numbers such as 123, but for large numbers such as 1234567891, it gives a segmentation fault error. This can be checked by trying to print the digits stored in fin_ans.
I tried using GDB Debugger, and got to know that the reason for Segmentation Fault lies in the while loop. I am sure that the functions divide_by_2 and is_zero are not the reason for Segmentation Fault, since I have tested them thoroughly.
I also used DrMemory, which indicated that I am trying to access (read or write) a memory location which has not been allocated. Unfortunately, I am not able to figure out where the error lies.
I suspect realloc() to be the cause of Segmentation Fault, but I am not sure.
Apologies for such a long question, however, I would highly appreciate any help provided to me for this code.
Thanks in advance for helping me out !
There are multiple problems in the code:
you do not check for memory allocation failure
you forget to free tmp_pointer before leaving the function.
you allocate a new array fin_ans to reserve the array tmp_pointer and perform the reverse operation but you do not return this array to the caller, nor do you have a way to return its size. You should change the prototype to return this information.
if the number of zero, the converted number should probably have 1 digit initialized as 0, but you use malloc which does not initialize the array it allocates so tmp_pointer[0] is uninitialized.
you did not provide the code for is_zero() nor divide_by_two(). It is possible that bugs in these functions cause the segmentation fault, especially if the loop does not reach zero and memory is eventually exhausted during this infinite loop.
Here is a modified version:
int *num_to_binary(int *number_b, int size_of_number, int *binary_size) {
int i, j, curr_size;
int *p, *newp;
curr_size = 1;
p = malloc(1 * sizeof(int));
if (p == NULL)
return NULL;
p[0] = 0;
for (i = 0; !is_zero(number_b, size_of_number); i++) {
if (i != 0) {
curr_size += 1;
newp = realloc(p, curr_size * sizeof(int));
if (newp == NULL) {
free(p);
return NULL;
}
p = newp;
}
p[i] = number_b[size_of_number - 1] % 2;
divide_by_2(number_b, size_of_number);
}
for (i = 0, j = curr_size; i < j; i++)
int digit = p[--j];
p[j] = p[i];
p[i] = digit;
}
*binary_size = curr_size;
return p;
}
There is no need for multiple memory reallocations. Result memory buffer size could be easily evaluated as binary logarithm of the decimal input value. Calculation of the number binary representation could also be simplified:
//Transform binary array to actual number
int arr2int(int* pIntArray, unsigned int nSizeIn) {
if (!pIntArray || !nSizeIn)
return 0;
int nResult = 0;
for (unsigned int i = 0; i < nSizeIn; ++i)
nResult += pIntArray[i] * (int)pow(10, nSizeIn - i - 1);
return nResult;
}
int* int2bin(int* pIntArray, unsigned int nSizeIn, unsigned int* nSizeOut){
//0) Converting int array to the actual value
int nVal = arr2int(pIntArray, nSizeIn);
//1)Evaluating size of result array and allocating memory
if(!nVal)
*nSizeOut = 1;
else
*nSizeOut = (int)floor(log2(nVal)) + 1;
//2)Allocate and init memory
int* pResult = malloc(*nSizeOut);
memset(pResult, 0, *nSizeOut * sizeof(int));
//3) Evaluate binary representation
for (unsigned int i = 0; i < *nSizeOut; ++i){
int nBinDigit = (int)pow(2, i);
if (nBinDigit == (nVal & nBinDigit))
pResult[*nSizeOut - i - 1] = 1;
}
return pResult;
}
Testing:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define _DC 9
int main()
{
int test[_DC];
for (int i = 0; i < _DC; ++i)
test[i] = i;
unsigned int nRes = 0;
int* pRes = int2bin(test, _DC, &nRes);
for (unsigned int i = 0; i < nRes; ++i)
printf("%d", pRes[i]);
free(pRes);
return 0;
}

Declare an Array without Size in C programming

I am writing a program that converts a given bit string (up to 32-bits) into decimal assuming the input is given in unsigned magnitude and two's complement. I am reading each bit in from the user one char at a time and attempting to store it into an array, but the array doesn't have a required size. Is there a way to get the array to go through the loop without the array size being known? I also am trying to figure out a way to not use the pow and multiplication functions. I am posting my code below, if you have any ideas please
#include "stdio.h"
#include "math.h"
#define MAX_BITS 32
#define ENTER '\n'
#define NUMBER_TWO 2
int main()
{
int unsignedMag;
int twosComp;
int negation[n];
int bitStore[n];
char enter;
//Input from the User
printf("Enter up to 32 bits (hit 'enter' to terminate early): ");
//Reads the first bit as a character
char bit = getchar();
while (getchar != enter) {
bit = bit - '0';
scanf("%c", &bitStore[bit]);
getchar();
}
//Terminates if user hits enter
if (bit == enter) {
return 0;
}
//Continue through code
else {
//Loop to calculate unsigned magnitude
for (int i = 0; i < bitStore[i]; i++) {
unsignedMag = unsignedMag + (bitStore[i] * pow(NUMBER_TWO, i));
}
//Loop to calculate complete negation
for (int j = 0; j < bitStore; j++) {
negation[j] = ~bitStore[j]
}
negation = negation + 1;
for (int l = 0; l < negation; l++) {
twosComp = twosComp + (negation[l] * pow(NUMBER_TWO, l));
}
}
return 0;
}
"Is there a way to get the array to go through the loop without the array size being known?"
No. Array sizes are fixed at the point the array is declared and the size is knownable: e.g. #Observer
size_t size = sizeof bitStore/sizeof bitStore[0];
Instead, since code has "given bit string (up to 32-bits) ", define the array as size 32 (or 33 is a string is desired).
Keep track of how much of the array was assigned.
//int bitStore[n];
int bitStore[MAX_BITS];
int count = 0;
// char bit = getchar();
int bit = getchar(); // Use `int` to account for potentially 257 different values
//while (getchar != enter) {
while (count < MAX_BITS && (bit == '0' || bit == '1')) {
bit = bit - '0';
// Do not read again, instead save result.
//scanf("%c", &bitStore[bit]);
bitStore[count++] = bit;
// getchar();
bit = getchar();
}
to not use the pow and multiplication functions.
Simply add or multiply by 2 via a shift. It is unclear why OP has a goal of not using "multiplication". I see little reason to prohibit *. A good compiler will emit efficient code when the underlying multiplication is expensive as *2 is trivial to optimize.
// int unsignedMag;
unsigned unsignedMag = 0; // initialize
// for (int i = 0; i < bitStore[i]; i++) {
for (int i = 0; i < count; i++) {
// preferred code, yet OP wants to avoid * for unclear reasons
// unsignedMag = unsignedMag*2 + bitStore[i];
unsignedMag = unsignedMag + unsignedMag + bitStore[i];
}
pow() is good to avoid for many reasons here. Most of all, using double math for an integer problem runs into precision issues with wide integers.
converts a given bit string (up to 32-bits) into decimal
Note that a bitStore[] array is not needed for this task. Simply form unsignedMag as data is read.

What should my constant mask value be for radix sort?

I was given a problem for one of my CS courses where I have to program a LSD radix sort that can sort unsigned integers (+ or -). It is given that the values to be sorted are 32-bit integer values.
The stipulation is that my mask must be a constant value, which is where my question lies. If I am doing an & bitwise operation on a 32-bit integer where each digit is represented by 4 bits (hexadecimal representation) should my mask be 28? (since I would like there to be 28 bits of 1's in binary)
Also if anyone could notices any additional errors, could you please bring attention to them?
#define BITS_PER_PASS 4
#define NUM_PASSES 8
#define NUM_BUCKETS 16
#define MASK 28
int *buckets[NUM_BUCKETS];
int bucket_sizes[NUM_BUCKETS];
void radix_sort( int *values, int n )
{
int i, j;
int bucket_index;
int *p;
for( i=0; i < NUM_PASSES; i++ )
{
for( j=0; j < NUM_BUCKETS; j++ )
{
bucket_sizes[j]=0;
}
for( j=0; j < n; j++ )
{
bucket_index = (values[j] & MASK) >> BITS_PER_PASS*i; //QUESTION
buckets[j][ bucket_sizes[bucket_index]]=values[j];
bucket_sizes[bucket_index]++;
}
p = values;
for( j=0; j < NUM_BUCKETS; j++ )
{
memcpy((void *)p, (void *)buckets[j], sizeof(int)*bucket_sizes[j]);
p+=bucket_sizes[j];
}
}
}
I would also like to add that all of the defined constants and global variables are mandatory since I was told to use these in my radix sort.
instead of this:
int *buckets[NUM_BUCKETS];
int bucket_sizes[NUM_BUCKETS];
...
buckets[j][ bucket_sizes[bucket_index]]=values[j];
suggest:
int buckets[NUM_BUCKETS];
int bucket_size[NUM_BUCKETS];
...
buckets[bucket_size[bucket_index]]=values[j];
regarding these lines:
bucket_index = (values[j] & MASK) >> BITS_PER_PASS*i;
I would expect something that extracts 4 bits, something like:
bucket_index = (values[j] >> BITS_PER_PASS*i) & MASK;
where MASK would be 0x0F, because trying to select one of 16 different 'buckets' ( where &0x0F will result in a value in the range 0...15)
I see you're using an array called bucket_sizes[NUM_BUCKETS] and array of pointers. These could be declared inside the sort function. For 32 bit unsigned integers, NUM_BUCKETS = 32/BITS_PER_PASS.
You also need a second buffer to hold the sorted values, for example, buffer = malloc(n * sizeof(unsigned int); Don't forget to free(buffer) when the sort is done.
The array of pointers should be set as buckets[0] = buffer, buckets[1] = buffer + bucket_sizes[0], buckets[2] = buffer + bucket_sizes[0] + bucket_sizes[1], ... . You can use a local variable to keep track of the sums of bucket sizes. Note that the last bucket_sizes[15] is not used to set the array of pointers.
After each pass swap buffer and values (treating them as pointers). Since it's an even number of passes, (8), the sorted data will end up back in values.

Using c and bit shifting to solve a specific requirement

I have a 16 letter alphabet. Given a sentence, I would like to count the frequency of each letter, and then encapsulate all frequencies in one number using clever bit shifting. Lets assume those sentences are always 100 letter each, and assuming no letter occurs more than 31 times, I would like something like this:
A: occurs 2 times -> 0010
B: occurs 10 times -> 1010
C: occurs 7 times -> 0111
Etc.
Now, I would like to concatenation those like this:
001010100111...
I just concentrated the frequencies above. To store the number easily, I wanted to convert the binary above to a 64 bit unsigned int.
My other requirement is to have that long and re extract the frequencies back per letter. So, I will need to be able to generate the decimal then parse it into the individual frequency bits.
How would I do that in c? I can do bit shifting and additions of those frequencies but that means I'm overlapping frequencies. The other issue is when extracting frequencies, how do I know how many bits to shift since trailing 0s are insignificant and not saved in the decimal but they are really important in my algorithm.
Any clever ideas? Thank you.
You have two problems: a mathematical problem and a coding problem.
Let's ignore the math problem for the moment. You can build an array with 16 integers and count the occurrences of each letter when you scan the text. If you assume that no letter occurs more than 15 times, then you don't have to worry about overflow and you can put the counts into your 64-bit integer easily enough. You'd write:
int counts[16]; // has the counts
unsigned long long freqs; // this holds the encoded value
// after you compute the counts
freqs = 0;
for (int i = 0; i < 16; ++i)
{
freqs <<= 4;
freqs |= (counts[i] & 0xF);
}
At that point, the count for the first letter is in the top 4 bits of freqs, and the count for the last letter is is the bottom four bits. All the other counts are in between. Each one occupies exactly 4 bits of that 64-bit number.
Now, if you want the ability to do this with much larger text, or a letter can occur more often than 15 times, you have to scale your numbers after counting so that the maximum is no larger than 15. That's the math problem I alluded to. I think you can probably figure out how to handle that one. You just have to scale the numbers.
Something like this should suffice:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
const static int SIZE = 16;
const static char ALPHABET[] = "0123456789ABCDEF";
char* getFrequency(char* str);
uint64_t getFrequencyNumber(char* freq);
int main() {
char* str = "1337CODE";
uint64_t freqNum = getFrequencyNumber(getFrequency(str));
printf("%llu\n",freqNum);
return 0;
}
char* getFrequency(char* str) {
int i,j;
char* freq = (char*) calloc(SIZE, sizeof(char));
for(i=0; str[i]; ++i)
for(j=0; j<SIZE; ++j)
if(str[i] == ALPHABET[j])
if(freq[i] < 15) //ignore overflow
(freq[j])++;
return freq;
}
uint64_t getFrequencyNumber(char* freq) {
uint64_t i,num;
for(i=num=0; i<SIZE; ++i)
num |= freq[i] << (4*i); //use bit shifting to concatenate 4 bit values
return num;
}
Try this, the advantage is that there will be no need of intermediate array to count your letters:
int ch_to_index(char ch) { return ch-'A'; }
unsigned long long get_freq(unsigned long long freq, int index)
{
return (freq>>(4*index))&0x0f;
}
unsigned long long set_freq(unsigned long long freq, int index, unsigned long val)
{
return ( ((val&0x0fULL)<<(4*index)) | (freq & (0xffffffffffffffffULL ^ (0xfULL<<(4*index)))) );
}
unsigned long long inc_freq(unsigned long long freq, int index)
{
return set_freq(freq, index, get_freq(freq, index) +1) ;
}
int main()
{
int i;
unsigned long long freq=0;
freq = inc_freq(freq, ch_to_index('A'));
freq = inc_freq(freq, ch_to_index('A'));
freq = inc_freq(freq, ch_to_index('B'));
for(i=0;i<16;i++)
{
printf("%i = %i\n", i, (int)get_freq(freq, i));
}
}
Existing answers are good; maybe the following is better though.
It is easy to use just one 64-bit number, and increment individual 4-bit parts in it.
For example, the following increases the counter for the 3rd, 5th and 13th letter (counting from 0):
uint64_t my_counters = 0;
my_counters += (uint64_t)1 << (4 * 3);
my_counters += (uint64_t)1 << (4 * 5);
my_counters += (uint64_t)1 << (4 * 13);
If your letters are consecutive in the ASCII table (for example, [a-p]), it is easy to calculate the index of the letter from its numerical value:
uint64_t my_counters = 0;
size_t i;
for (i = 0; str[i] != '\0'; ++i)
{
int index = str[i] - 'a';
my_counters += (uint64_t)1 << (4 * index);
}
To print:
char c;
for (c = 'a'; c <= 'p'; ++c)
{
int index = c - 'a';
int counter = (int)((my_counters >> (4 * index)) & 0xf);
printf("Letter %c, count %d\n", c, counter);
}
Note: my code concatenates the bits in the opposite order comparing to what you want; it seems that this way makes it more clear. You can reverse the order if you replace 4 * index by 60 - 4 * index.

Converting int to int[] in 'C'

I basically want to convert a given int number and store individual digits in an array for further processing.
I know I can use % and get each digit and store it. But the thing is if I do not know the number of digits of the int till runtime and hence I cannot allocate the size of the array. So, I cannot work backwards (from the units place).
I also do not want to first store the number backwords in an array and then again reverse the array.
Is there any other way of getting about doing this?
Eg: int num = 12345;
OUTPUT: ar[0] = 1, ar[1] = 2 and so on, where ar[] is an int array.
Convert is probably not the right word. You can take the int, dynamically allocate a new int[], and then store the digits of the int into the int[]. I'm using log base 10 to calculate how many digits num has. Include math.h to use it. The following code is untested, but will give you an idea of what to do.
int num = 12345;
int size = (int)(log10(num)+1);
// allocate array
int *digits = (int*)malloc(sizeof(int) * size);
// get digits
for(int i=size-1; i>=0; --i) {
digits[i] = num%10;
num=num/10; // integer division
}
The easiest way is to calculate number of digits to know the size of an array you need
int input = <input number>; // >= 0
int d, numdigits = 1;
int *arr;
d = input;
while (d /= 10)
numdigits++;
arr = malloc(sizeof(int) * numdigits);
There's even easier way: probably you pass a number to your program as an argument from command line. In this case you receive it as a string in argp[N], so you can just call strlen(argp[N]) to determine number of digits in your number.
If you have a 32-bit integer type, the maximum value will be comprised of 10 digits at the most (excluding the sign for negative numbers). That could be your upper limit.
If you need to dynamically determine the minimum sufficient size, you can determine that with normal comparisons (since calling a logarithmic function is probably more expensive, but a possibility):
size = 10;
if (myint < 1000000000) size--;
if (myint < 100000000) size--;
/* ... */
Declaring the array to be of a dynamic size depends on the C language standard you are using. In C89 dynamic array sizes (based on values calculated during run-time) is not possible. You may need to use dynamically allocated memory.
HTH,
Johan
The following complete program shows one way to do this. It uses unsigned integers so as to not have to worry about converting - you didn't state what should happen for negative numbers so, like any good consultant, I made the problem disappear for my own convenience :-)
It basically works out the required size of an array and allocates it. The array itself has one element at the start specifying how many elements are in the array (a length int).
Each subsequent element is a digit in sequence. The main code below shows how to process it.
If it can't create the array, it'll just give you back NULL - you should also remember to free the memory passed back once you're done with it.
#include <stdio.h>
#include <stdlib.h>
int *convert (unsigned int num) {
unsigned int *ptr;
unsigned int digits = 0;
unsigned int temp = num;
// Figure out how many digits in the number.
if (temp == 0) {
digits = 1;
} else {
while (temp > 0) {
temp /= 10;
digits++;
}
}
// Allocate enough memory for length and digits.
ptr = malloc ((digits + 1) * sizeof (unsigned int));
// Populate array if we got one.
if (ptr != NULL) {
ptr[0] = digits;
for (temp = 0; temp < digits; temp++) {
ptr[digits - temp] = num % 10;
num /= 10;
}
}
return ptr;
}
That convert function above is the "meat" - it allocates an integer array to place the length (index 0) and digits (indexes 1 through N where N is the number of digits). The following was the test program I used.
int main (void) {
int i;
unsigned int num = 12345;
unsigned int *arr = convert (num);
if (arr == NULL) {
printf ("No memory\n");
} else {
// Length is index 0, rest are digits.
for (i = 1; i <= arr[0]; i++)
printf ("arr[%d] = %u\n", i, arr[i]);
free (arr);
}
return 0;
}
The output of this is:
arr[1] = 1
arr[2] = 2
arr[3] = 3
arr[4] = 4
arr[5] = 5
You can find out the number of digits by taking the base-10 logarithm and adding one. For that, you could use the log10 or log10f functions from the standard math library. This may be a bit slower, but it's probably the most exact as long as double has enough bits to exactly represent your number:
int numdigits = 1 + log10(num);
Alternatively, you could repeatedly divide by ten until the result is zero and count the digits that way.
Still another option is just to allocate enough room for the maximum number of digits the type can have. For a 32-bit integer, that'd be 10; for 64-bit, 20 should be enough. You can just zero the extra digits. Since that's not a lot of wasted space even in the worst case, it might be the simplest and fastest option. You'd have to know how many bits are in an int in your setup, though.
You can also estimate fairly well by allocating 3 digits for each 10 bits used, plus one. That should be enough digits unless the number of bits is ridiculously large (way above the number of digits any of the usual int types could have).
int numdigits = 1
unsigned int n = num;
for (n = num; n & 0x03ff; n >>= 10)
numdigits += 3;
/* numdigits is at least the needed number of digits, maybe up to 3 more */
This last one won't work (directly) if the number is negative.
What you basically want to do is to transform your integer to an array of its decimal positions. The printf family of functions perfectly knows how to do this, no need to reinvent the wheel. I am changing the assignment a bit since you didn't say anything about signs, and it simply makes more sense for unsigned values.
unsigned* res = 0;
size_t len = 0;
{
/* temporary array, large enough to hold the representation of any unsigned */
char positions[20] = { 0 };
sprintf(position, "%u", number);
len = strlen(position);
res = malloc(sizeof(unsigned[len]));
for (size_t i = 0; i < len; ++i)
res[i] = position[i] - '0';
}

Resources