Самый простой способ повторить последовательность байтов в больший буфер в C ++ - PullRequest
5 голосов
/ 13 марта 2009

Дано (на С ++)

char * byte_sequence;
size_t byte_sequence_length;
char * buffer;
size_t N;

Предполагается, что byte_sequence и byte_sequence_length инициализируются с некоторой последовательностью байтов произвольной длины (и ее длиной), а buffer инициализируется так, чтобы указывать на N * byte_sequence_length байтов, что будет самым простым способом репликации byte_sequence в buffer N раз? Есть ли в STL / BOOST что-нибудь, что уже делает что-то подобное?

Например, если бы последовательность была "abcd", а N была 3, тогда buffer в конечном итоге содержал бы "abcdabcdabcd".

Ответы [ 4 ]

12 голосов
/ 13 марта 2009

Я бы, наверное, просто сказал:

for (int i=0; i < N; ++i)
    memcpy(buffer + i * byte_sequence_length, byte_sequence, byte_sequence_length);

Предполагается, что вы имеете дело с двоичными данными и отслеживаете длину, не используя '\0' завершение.

Если вы хотите, чтобы это были c-строки, вам нужно выделить дополнительный байт и добавить в конце '\0' a. Учитывая c-строку и целое число, вы хотели бы сделать это так:

char *RepeatN(char *source, size_t n)
{
    assert(n >= 0 && source != NULL);            
    size_t length = strlen(source) - 1;
    char *buffer = new char[length*n + 1];
    for (int i=0; i < n; ++i)
        memcpy(buffer + i * length, source, length);
    buffer[n * length] = '\0';
}
7 голосов
/ 13 марта 2009

Повтор буфера, избегая арифметики с указателями:

Вы можете использовать std :: vector или std :: string, чтобы вам было проще. Оба этих контейнера также могут содержать двоичные данные.

Это решение обладает хорошими свойствами:

  • Вам не нужно беспокоиться о нарушениях доступа к памяти
  • Вам не нужно беспокоиться о получении размера вашего буфера правильного
  • Вы можете добавлять последовательности в любой момент в ваш буфер без перераспределения вручную

.

//Note this works even for binary data.
void appendSequenceToMyBuffer(std::string &sBuffer
       , const char *byte_sequence
       , int byte_sequence_length
       , int N)
{
  for(int i = 0; i < N; ++i)
      sBuffer.append(byte_sequence, byte_sequence_length);
}

//Note: buffer == sBuffer.c_str()

Альтернатива: для двоичных данных с использованием memcpy:

buffer = new char[byte_sequence_length*N];
for (int i=0; i < N; ++i)
  memcpy(buffer+i*byte_sequence_length, byte_sequence, byte_sequence_length); 
//...
delete[] buffer;

Alternate: для строк с нулевым символом в конце, используя strcpy:

buffer = new char[byte_sequence_length*N+1];
int byte_sequence_length = strlen(byte_sequence);
for (int i=0; i < N; ++i)
  strcpy(buffer+i*byte_sequence_length, byte_sequence, byte_sequence_length); 
//...
delete[] buffer;

Альтернатива: если вы заполняете буфер одним значением:

buffer = new char[N];
memset(buffer, byte_value, N);
//...
delete[] buffer;
4 голосов
/ 13 марта 2009

Вы можете использовать алгоритм STL Generate:

MSDN: Создать

3 голосов
/ 13 марта 2009

Если известно, что N является степенью 2, вы можете копировать из первой части вашего буфера в последующие части, увеличивая количество копий каждый раз:

assert((N > 0) && ((N & (N-1)) == 0));
memcpy(buffer, byte_sequence, byte_sequence_length);
for (size_t i = 1;  i < N;  i *= 2)
    memcpy(buffer + i * byte_sequence_length, buffer, i * byte_sequence_length);

Редактировать: Тривиально расширить это для работы, когда N не степень 2. Вот улучшенная версия, которая удаляет все ограничения на N, а также заменяет нечетное для заявления с какое-то время.

if (N > 0)
    memcpy(buffer, byte_sequence, byte_sequence_length);
size_t copied = 1;
while (copied < N)
{
    size_t tocopy = min(copied, N - copied);
    memcpy(buffer + copied * byte_sequence_length, buffer, tocopy * byte_sequence_length);
    copied += tocopy;
}
...