Разбить строку по 8 бит и перевести

Дана последовательность из ? битов, каждый бит имеет значение 0 или 1. Нужно разделить эту последовательность на байты, по 8 битов в каждом (в последний байт может попасть меньше битов). После этого нужно распечатать значения всех полученных байтов в привычной людям десятичной системе исчисления. Биты внутри байта записываются в привычном современным компьютерам порядке little-endian: сначала идут младшие биты, потом старшие. В первой строке входного файла записано одно целое число ? — количество битов в последовательности. Во второй строке записано ровно ? символов 0 или 1: значения битов последовательности. после второй строки файла символ перевода строки может быть, а может не быть. Мой код представлен ниже. Сколько ни бьюсь с ним - неверный ответ на выходе. Подскажите тупящему новичку, что можно сделать/исправить?

#include<stdio.h>
#include<math.h>
int main(){
    int N, i, v;
    scanf("%d", &N);
    int p[N-1];
    for (i=0; i<=N-1; i+=8){
        v=((p[i]*(pow(2,i)))+(p[i+1]*(pow(2,(i+1))))+(p[i+2]*(pow(2,(i+2))))+(p[i+3]*(pow(2,(i+3))))+(p[i+4]*(pow(2,(i+4))))+(p[i+5]*(pow(2,(i+5))))+(p[i+6]*(pow(2,(i+6))))+(p[i+7]*(pow(2,(i+7)))));
        printf("%d", v);
    }
}

Ответы (2 шт):

Автор решения: Zhihar

тихий ужас :)

во-первых вместо pow(2, i) лучше использовать 1 << i - т.е. битовое смещение 1чки вправо - это равносильно возведению в степень 2, только ГОРАЗДО быстрее и не требует подключения дополнительных библиотек

Как бы я сделал алгоритм:

  1. перемещаемся в цикле по 8 и накапливаем байт

     value = 0;
     for (int index = 0; index < 8; index ++)
         value += buf[index] << index;
    
  2. по буферу p шел бы с через предыдущий цикл

     int pos = 0;
     while (pos < N) {
    
         int* buf = (int*)p + pos;
    
         value = 0;
         for (int index = 0; index < 8; index ++)
             value += buf[index] << index;
    
         pos += 8;
     }
    
  3. и конечно надо учесть, что на последнем байте может потребоваться менее 8 шагов цикла:

     const int size = (N - pos >= 8) ? 8 : (N - pos); 
    

В итоге алгоритм был бы таким:

int pos = 0;
while (pos < N) {

    int* buf = (int*)p + pos;

    const int size = (N - pos >= 8) ? 8 : (N - pos); 

    value = 0;

    for (int index = 0; index < pos; index ++)
        value += buf[index] << index;

    // тут выводим value в требуемом виде

    pos += 8;
}

Конечно считаем, что в массиве p уже записаны числа

Если в нем записаны буквы, тогда надо так:

int pos = 0;
while (pos < N) {

    char* buf = (char*)p + pos;

    const int size = (N - pos >= 8) ? 8 : (N - pos); 

    value = 0;

    for (int index = 0; index < pos; index ++) {
        const int bit = (buf[index] == '0') ? 0 : 1;
        value += bit  << index;
    }

    // тут выводим value в требуемом виде

    pos += 8;
}

P.S.

если я не перепутал бигэниан и литлэндиан, иначе придется так:

value += buf[index] << (7 - index);
→ Ссылка
Автор решения: wololo

Попробуйте так:

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

int main(void) 
{
    size_t N = 0;
    scanf("%zu", &N);

    size_t num_of_bytes = N / 8 + (N % 8 != 0);
    uint_least8_t* buff = malloc(num_of_bytes * sizeof(uint_least8_t));
    if (!buff)
        return EXIT_FAILURE;

    int buff_pos = 0;
    int byte = 0, digit_shift = 0, digit = 0;
    for (size_t i = 0; i < N; ++i)
    {
        scanf("%1d", &digit);

        byte += digit << digit_shift;
        ++digit_shift;
        if (digit_shift == 8)
        {
            buff[buff_pos] = byte;
            ++buff_pos;
            byte = 0;
            digit_shift = 0;
        }
    }
    if (N % 8 != 0)
        buff[buff_pos] = byte;

    for (size_t i = 0; i < num_of_bytes; ++i)
        printf("%" PRIuLEAST8 " ", buff[i]);
    free(buff);
    
    return 0;
}

Пример ввода:

27
11111111 00000001 01010101 011

Вывод:

255 128 170 6 
→ Ссылка