new и malloc выделяют дополнительные 16 байтов - PullRequest
2 голосов
/ 22 февраля 2012

Я пишу на c ++ в VS2010 Windows 7. Я пытаюсь прочитать файл размером 64 байта.Вот код:

    BYTE* MyReadFile(FILE *f)
{
    size_t result;
    BYTE *buffer;
    long lSize;
    if (f == NULL) 
    {
        fputs ("File error", stderr); 
        exit (1);
    }

    fseek (f, 0, SEEK_END);
    lSize = ftell (f);
    rewind (f);

    //buffer = (BYTE*) malloc (sizeof(char)*lSize);
    buffer = new BYTE[lSize];
    if (buffer == NULL) 
    {
        fputs ("Memory error", stderr); 
        exit (2);
    }

    result = fread (buffer, 1, lSize, f);
    if (result != lSize) 
    {
        fputs ("Reading error",stderr); 
        exit (3);
    }

    fclose (f);
    return buffer;
}

Когда я получаю размер файла, он равен 64, но когда я выделяю для него память новым BYTE [lSize], я получаю 80 байт пространства и, таким образом, странную последовательность ээээ ««« «« «« Оюою добавляется в конец буфера.Подскажите, пожалуйста, как с этим справиться?

Ответы [ 4 ]

4 голосов
/ 22 февраля 2012

Существует важное различие между количеством выделенных байтов и количеством байтов, которые вы видите.

Если lsize равен 64, вы действительно выделили себе 64 байта. Это не означает, что за экраном C ++ во время выполнения запросит у Windows ровно 64 байта. На практике менеджеры памяти требуют немного больше памяти, чтобы они могли выполнять свою домашнюю работу. Часто эти дополнительные байты выделяются ПЕРЕД указателем, возвращаемым из new / malloc, поэтому вы их никогда не увидите.

Однако это не ваша проблема. Проблема в том, что вы читаете 64 байта из файла, используя fread. Фред не знает, какие данные вы читаете. Это может быть структура, буфер символов, набор парных чисел ... Он просто читает эти байты для вас.

Это означает, что если файл содержит символы «ABC», вы получите именно «ABC». НО, в C строки должны заканчиваться нулем, поэтому если вы передадите этот буфер в printf, он продолжит сканирование памяти, пока не найдет нуль-символ.

Итак, чтобы решить вашу проблему, выделите еще 1 байт и установите последний байт в нулевой символ, например:

buffer = new BYTE[lSize+1]; 
buffer[lSize] = '\0';
4 голосов
/ 22 февраля 2012

То, что находится позади и выше, называется sentinel. Он используется для проверки, не превышает ли ваш код границы выделенной памяти. Когда ваша программа перезаписывает эти значения, библиотека CRT сообщит об отладочных сообщениях, когда вы освободите свой буфер.

Смотрите здесь: http://msdn.microsoft.com/en-us/library/ms220938%28v=vs.80%29.aspx

enter image description here

3 голосов
/ 22 февраля 2012

Хотя это может выглядеть как проблема с памятью, на самом деле это проблема печати (как указал @Mystical).Вам нужно поставить нулевое завершение, если вы собираетесь распечатать что-либо в виде строки, иначе память будет считываться в произвольном порядке до тех пор, пока она не будет найдена (то есть UB).

Попробуйте вместо этого:

buffer = new BYTE[lSize + 1];
if (buffer == NULL) 
{
    fputs ("Memory error", stderr); 
    exit (2);
}

result = fread (buffer, 1, lSize, f);
if (result != lSize) 
{
    fputs ("Reading error",stderr); 
    exit (3);
}

buffer[lSize] = '\0';

Это обеспечит наличие нулевого терминатора в конце возвращаемого буфера.

1 голос
/ 22 февраля 2012

Когда память выделена, она не на байтовой основе.Вместо этого он размещается в выровненных блоках по 8 или 16 байтов (возможно, с заголовком в начале, перед указателем).Обычно это не проблема, если вы не создаете много (много миллионов) маленьких объектов.Это не должно быть проблемой в C и даже не является серьезной проблемой в Java (которая не поддерживает массив объектов или объектов, размещенных в стеке).

...