1

So I have an array of characters like the following {h,e,l,l,o,o} so I need first to translate this to its bit representation, so what I would have is this

h = 01101000
e = 01100101
l = 01101100
l = 01101100
o = 01101111
o = 01101111

I need divide all of this bits in groups of five and save it to an array so for example the union of all this characters would be

011010000110010101101100011011000110111101101111

And now I divide this in groups of five so

01101 00001 10010 10110 11000 11011 00011 01111 01101 111

and the last sequence should be completed with zeros so it would be 00111 instead. Note: Each group of 5 bits would be completed with a header in order to have 8 bits.

So I havent realized yet how to accomplish this, because I can extract the 5 bits of each character and get the representation of each character in binary as following

 for (int i = 7; i >= 0; --i)
  {
     printf("%c", (c & (1 << i)) ? '1' : '0');
  }

The problem is how to combine two characters so If I have two characters 00000001 and 11111110 when I divide in five groups I would have 5 bits of the first part of the character and for the second group I would have 3 bits from the last character and 2 from the second one. How can I make this combination and save all this groups in an array?

ravelinx
  • 1,557
  • 4
  • 18
  • 26
  • The thing that you want to achieve doesn't make sense. – Iharob Al Asimi Oct 15 '16 at 21:46
  • This is almost the same as base64. Base64 stores 6 bits per character. Much like what you want except base64 collects the extra 2 bits from every 3 bytes and makes each 4th byte using the 6 extra bits from the previous 3 bytes. – doug65536 Oct 15 '16 at 21:51
  • @doug65536 To each group of 5 bits I would add a header to complete the 8 bits, the thing is that I cant figure out how to get all this five groups – ravelinx Oct 15 '16 at 21:53
  • Can't you just build a string by concatenating the results of `'h' = "01101000" ....` and then taking the characters in groups of five until there are fewer than 5 left, padding the final group. – ad absurdum Oct 15 '16 at 21:58
  • @ravelinx You should say that you want to add a header. You will want to make a byte from the appropriate number of bytes. What would be the header that you want? – Iharob Al Asimi Oct 15 '16 at 21:59
  • @iharob Ok, I have modified my question, but the thing is that adding the header is not the problem for me, the thing is dividing the bits in groups – ravelinx Oct 15 '16 at 22:00
  • @DavidBowling How can I achieve this in c? – ravelinx Oct 15 '16 at 22:01
  • 1
    A loop, some variables to keep track of the bit offsets, some shifting and masking, and an output buffer. – doug65536 Oct 15 '16 at 22:02
  • @ravelinx-- I added an answer that you should be able to use. You can probably clean up the code a bit. – ad absurdum Oct 16 '16 at 00:44

3 Answers3

1

Assuming that a byte is made of 8 bits (ATTENTION: the C standard doesn't guarantee this), you have to loop over the string and play with bit operations to get it done:

  • >> n right shift to get rid of the n lowest bits
  • << n to inject n times a 0 bit in the lowest position
  • & 0x1f to keep only the 5 lowest bits and reset the higer bits
  • | to merge high bits and low bits, when the overlapping bits are 0

This can be coded like this:

char s[]="helloo";

unsigned char last=0;          // remaining bits from previous iteration in high output part
size_t j=5;                    // number of high input bits to keep in the low output part 
unsigned char output=0; 
for (char *p=s; *p; p++) {     // iterate on the string 
    do {
        output = ((*p >> (8-j)) | last) & 0x1f;  // last high bits set followed by j bits shifted to lower part; only 5 bits are kept 
        printf ("%02x ",(unsigned)output);
        j += 5;                                  // take next block  
        last = (*p << (j%8)) & 0x1f;             // keep the ignored bits for next iteration 
    } while (j<8);                               // loop if second block to be extracted from current byte
    j -= 8;                                      
}
if (j)                                           // there are trailing bits to be output
   printf("%02x\n",(unsigned)last); 

online demo

The displayed result for your example will be (in hexadecimal): 0d 01 12 16 18 1b 03 0f 0d 1c, which corresponds exactly to each of the 5 bit groups that you have listed. Note that this code ads 0 right padding in the last block if it is not exactly 5 bits long (e.g. here the last 3 bits are padded to 11100 i.e. 0x1C instead of 111 which would be 0x0B)

You could easily adapt this code to store the output in a buffer instead of printing it. The only delicate thing would be to precalculate the size of the output which should be 8/5 times the original size, to be increased by 1 if it's not a multiple of 5 and again by 1 if you expect a terminator to be added.

Christophe
  • 68,716
  • 7
  • 72
  • 138
1

Here is some code that should solve your problem:

#include <stdio.h>
#include <string.h>

int main(void)
{
    char arr[6] = {'h', 'e', 'l', 'l', 'o', 'o'};
    char charcode[9];
    char binarr[121] = "";
    char fives[24][5] = {{0}};
    int i, j, n, numchars, grouping = 0, numgroups = 0;

    /* Build binary string */
    printf("\nCharacter encodings:\n");
    for (j = 0; j < 6; j++) {
        for (i = 0, n = 7;  i < 8; i++, n--)
            charcode[i] = (arr[j] & (01 << n)) ? '1' : '0';
        charcode[8] = '\0';
        printf("%c = %s\n", arr[j], charcode);
        strcat(binarr, charcode);
    }

    /* Break binary string into groups of 5 characters */
    numchars = strlen(binarr);
    j = 0;
    while (j < numchars) {
        i = 0;
        if ((numchars - j) < 5) {                 // add '0' padding
            for (i = 0; i < (5 - (numchars - j)); i++)
                fives[grouping][i] = '0';
        }
        while (i < 5) {                           // write binary digits
            fives[grouping][i] = binarr[j];
            ++i;
            ++j;
        }
        ++grouping;
        ++numgroups;
    }

    printf("\nConcatenated binary string:\n");
    printf("%s\n", binarr);

    printf("\nGroupings of five, with padded final grouping:\n");
    for (grouping = 0; grouping <= numgroups; grouping++) {
        for (i = 0; i < 5; i++)
            printf("%c", fives[grouping][i]);
        putchar(' ');
    }
    putchar('\n');

    return 0;
}

When you run this as is, the output is:

Character encodings:
h = 01101000
e = 01100101
l = 01101100
l = 01101100
o = 01101111
o = 01101111

Concatenated binary string:
011010000110010101101100011011000110111101101111

Groupings of five, with padded final grouping:
01101 00001 10010 10110 11000 11011 00011 01111 01101 00111  
ad absurdum
  • 19,498
  • 5
  • 37
  • 60
1
#include <limits.h>
#include <stdio.h>

#define GROUP_SIZE 5

static int nextBit(void);
static int nextGroup(char *dest);

static char str[] = "helloo";

int main(void) {
    char bits[GROUP_SIZE + 1];
    int firstTime, nBits;

    firstTime = 1;
    while ((nBits = nextGroup(bits)) == GROUP_SIZE) {
        if (!firstTime) {
            (void) putchar(' ');
        }
        firstTime = 0;
        (void) printf("%s", bits);
    }
    if (nBits > 0) {
        if (!firstTime) {
            (void) putchar(' ');
        }
        while (nBits++ < GROUP_SIZE) {
            (void) putchar('0');
        }
        (void) printf("%s", bits);
    }
    (void) putchar('\n');
    return 0;
}

static int nextBit(void) {
    static int bitI = 0, charI = -1;

    if (--bitI < 0) {
        bitI = CHAR_BIT - 1;
        if (str[++charI] == '\0') {
            return -1;
        }
    }
    return (str[charI] & (1 << bitI)) != 0 ? 1 : 0;
}

static int nextGroup(char *dest) {
    int bit, i;

    for (i = 0; i < GROUP_SIZE; ++i) {
        bit = nextBit();
        if (bit == -1) {
            break;
        }
        dest[i] = '0' + bit;
    }
    dest[i] = '\0';
    return i;
}
potrzebie
  • 1,768
  • 1
  • 12
  • 25