Инициализация указателя? для конкретной функции

Хорошо, это меня немного озадачило.

следующая функция кодирует строку в base 64

void Base64Enc(const unsigned char *src, int srclen, unsigned char *dest)
{
    static const unsigned char enc[] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    unsigned char *cp;
    int i;

    cp = dest;
    for(i = 0; i < srclen; i += 3) 
    {
      *(cp++) = enc[((src[i + 0] >> 2))];
      *(cp++) = enc[((src[i + 0] << 4) & 0x30)
                    | ((src[i + 1] >> 4) & 0x0f)];
      *(cp++) = enc[((src[i + 1] << 2) & 0x3c)
                    | ((src[i + 2] >> 6) & 0x03)];
      *(cp++) = enc[((src[i + 2]     ) & 0x3f)];
    }
    *cp = '\0';
    while (i-- > srclen)
      *(--cp) = '=';

    return;
}

Теперь при вызове функции Base64Enc() у меня есть:

unsigned char *B64Encoded;

Какой аргумент я передаю на unsigned char *dest в функции кодирования base 64. Я пробовал разные инициализации от mallocs до NULL до другой инициализации. Независимо от того, что я делаю, я всегда получаю исключение, и если я его не инициализирую, то компилятор (компилятор VS2005 C) выдает предупреждение о том, что он не был инициализирован. Если я запускаю этот код с неинициализированной переменной, иногда он работает, а иногда нет. Как мне инициализировать этот указатель и передать его функции?


person wonderer    schedule 24.06.2009    source источник


Ответы (5)


вам нужно выделить достаточно большой буфер, чтобы содержать закодированный результат. Либо разместите его в стеке, например:

unsigned char B64Encoded[256]; // the number here needs to be big enough to hold all possible variations of the argument

Но при таком подходе легко вызвать переполнение буфера стека, выделив слишком мало места. Было бы намного лучше, если бы вы выделили его в динамической памяти:

int cbEncodedSize = srclen * 4 / 3 + 1;  // cbEncodedSize is calculated from the length of the source string
unsigned char *B64Encoded = (unsigned char*)malloc(cbEncodedSize);

Не забудьте освободить () выделенный буфер после того, как закончите.

person Rom    schedule 24.06.2009
comment
Ваш первый пример (unsigned char* B64Encoded[256];) неверен - он должен быть: (unsigned char B64Encoded[256]) - вы создаете массив из 256 символов, а не 256 символов. - person DaveR; 25.06.2009

Похоже, вы хотели бы использовать что-то вроде этого:

// allocate 4/3 bytes per source character, plus one for the null terminator
unsigned char *B64Encoded = malloc(srclen*4/3+1);

Base64Enc(src, srclen, B64Encoded);
person 1800 INFORMATION    schedule 24.06.2009
comment
(srclen + 1) недостаточно для кодировки base64. Приведенный выше пример вызовет переполнение буфера внутри функции Base64Enc(). - person Rom; 25.06.2009

Было бы полезно, если бы вы указали ошибку.

Я могу с вашей функцией выше сделать это успешно:

int main() {
    unsigned char *B64Encoded;
    B64Encoded = (unsigned char *) malloc (1000);
    unsigned char *src = "ABC";
    Base64Enc(src, 3, B64Encoded);

}

Вам определенно нужно выделить место для данных. Вам также нужно выделить больше места, чем src (я думаю, на 1/4 больше).

person Jamie Love    schedule 24.06.2009

Строка в кодировке base64 имеет четыре байта на три байта в строке данных, поэтому, если srclen равно 300 байтам (или символам), длина строки в кодировке base64 равна 400.

В В Википедии есть короткая, но неплохая статья об этом.

Таким образом, округление srclen до ближайшего кортежа из трех, разделенных на три, умноженных на четыре, должно быть ровно достаточным объемом памяти.

person ralphtheninja    schedule 24.06.2009

Я вижу проблему в вашем коде в том, что он может получить доступ к байту после конечного нулевого символа, например, если длина строки составляет один символ. В этом случае поведение не определено и может привести к возникновению исключения, если активирована проверка границ буфера.

Это может объяснить сообщение, связанное с доступом к неинициализированной памяти.

Затем вы должны изменить свой код, чтобы обрабатывать конечные символы отдельно.

int len = (scrlen/3)*3;
for( int i = 0; i < len; i += 3 )
{
  // your current code here, it is ok with this loop condition.
}

// Handle 0 bits padding if required
if( len != srclen )
{
   // add new code here
}

...

PS: Вот страница в Википедии, описывающая кодировку Base64.

person chmike    schedule 25.06.2009