Инициализация указателя? для конкретной функции - PullRequest
1 голос
/ 25 июня 2009

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

следующая функция кодирует строку в базу 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 для другой инициализации. Независимо от того, что я делаю, я всегда получаю исключение, и если я его не инициализирую, то компилятор (компилятор C VS2005) выдает предупреждение о том, что оно не было инициализировано. Если я запускаю этот код с неинициализированной переменной, иногда он работает, а некоторые другие - нет. Как мне инициализировать этот указатель и передать его функции?

Ответы [ 5 ]

1 голос
/ 25 июня 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 кодировка .

1 голос
/ 25 июня 2009

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

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

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

1 голос
/ 25 июня 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);
1 голос
/ 25 июня 2009

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

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

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

}

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

1 голос
/ 25 июня 2009

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

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);

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...