This program has Undefined Behaviour from accessing uninitialized values of list
. I'm going to refactor this code so its easier to talk about, but know this refactored code is still incorrect.
x
is always 0
. y
is always 1
. x++
has no effect. This function can be rewritten as:
void bin(unsigned n)
{
char list[6];
if (n > 1)
bin(n / 2);
list[0] = n % 2;
for (int i = 0; i < 5; i++) {
if (list[i] == 1) {
switch (i) {
case 5: printf("321"); break;
case 4: printf("161"); break;
case 3: printf("81"); break;
case 2: printf("41"); break;
case 1: printf("21"); break;
case 0: printf("11"); break;
}
}
}
}
There are some problems here.
Firstly, list
is not shared between calls to bin
, nor are any other variables.
In every call to bin
, only list[0]
is assigned a value - all others indices contain uninitialized values. You are (un)lucky in that these values are seemingly never 1
.
With your example of 12
as the starting value:
When you initially call bin(12)
, what happens is:
bin(12)
calls bin(6)
, bin(6)
calls bin(3)
, bin(3)
calls bin(1)
.
Starting from the end and working backwards, in bin(1)
:
n = 1
, so list[0] = n % 2;
assigns 1
. The loop checks each element of list
for the value 1
, finds it when the index (i
) equals 0
, and prints 11
.
This is repeated in bin(3)
, as 3 % 2
is also 1
, and again this result is assigned to the first element of list
. Again, we print 11
.
In bin(6)
, 6 % 2
is 0
. The loop finds no elements of list
that equal 1
. Nothing is printed.
And again, this is repeated in bin(12)
, as 12 % 2
is 0
. Nothing is printed.
To reiterate, it is pure luck that this program appears to work. Accessing list[1]
through list[4]
(i < 5
ensures you never access the last element) in each function call is Undefined Behaviour. It is generally not worth reasoning about a program once UB has been invoked.
When dealing with bits, it would be a good time to use some bitwise operators.
Here is a program that more-or-less does what you have described.
It assumes 32-bit unsigned
(consider using fixed width types from <stdint.h>
to be more precise).
This program works by repeatedly shifting the bits of our initial value to the right b
number of places and testing if the rightmost bit is set.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
unsigned num = argc > 1 ? atoi(argv[1]) : 42;
unsigned b = 32;
while (b--)
if ((num >> b) & 1)
printf("%u1 ", 1 << b);
putchar('\n');
}
$ ./a.out 12
81 41