Почему malloc выделяет количество байтов, отличное от запрошенного?

У меня есть этот фрагмент кода

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

int main(){
    void *a, *b;

    a = malloc(16);
    b = malloc(16);
    printf("\n   block size (for a): %p-%p : %li", b, a, b-a);

    a = malloc(1024);
    b = malloc(1024);
    printf("\n   block size (for a): %p-%p : %li", b, a, b-a);  
}

Разве это не должно печатать последний выделенный размер блока (16 или 1024)? Вместо этого он печатает 24 и 1032, поэтому объем выделенной памяти, кажется, имеет 8 дополнительных байтов.

Моя проблема в том, что (до создания этого тестового примера) я выполняю malloc() в функции (1024 байта) и возвращаю выделенный результат. При проверке размера блока при возврате функции я получаю 516 блоков ... и я не понимаю почему. Я предполагаю, что это может быть причиной повреждения памяти, которое происходит после некоторой обработки выделенных буферов :)

Редактировать: Я видел Как я могу получить размер массива из указателя в C? и, кажется, спрашивает то же самое, извините за репост.

Я переделал свой пример в свой более конкретный код:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

short int * mallocStuff(long int number, short int base){
    short int *array;
    int size=1024;

    array=(short int*)calloc(1,size);
    //array=(short int*)malloc(size);

    return array;
}

int main(){
    short int **translatedArray;

    translatedArray=malloc(4*sizeof(short int));

    int i;
    for(i=0;i<4;i++){
        translatedArray[i]=mallocStuff(0,0);

        if (i>0)
            printf("\n   block size (for a): %p-%p : %i",
                translatedArray[i], translatedArray[i-1], translatedArray[i]-translatedArray[i-1]);
    }

    return 0;
}

И на выходе

   block size (for a): 0x804a420-0x804a018 : 516
   block size (for a): 0x804a828-0x804a420 : 516
   block size (for a): 0x804ac30-0x804a828 : 516

Согласно вышеупомянутому сообщению, это больше 1024. Я ошибаюсь?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
10
0
23 231
12
Перейти к ответу Данный вопрос помечен как решенный

Ответы 12

Перед указателем стоит размер следующего массива, который представляет собой 32- или 64-битное целое число (не знаю, со знаком или без знака)

Функция malloc всегда выделяет немного больше, чем вы запрашиваете, для хранения некоторой бухгалтерской информации. В конце концов, когда вы вызываете free(), он должен знать, насколько велик блок.

Кроме того, обычно реализации malloc округляют запрошенный размер до следующего кратного 8 или 16 или некоторого другого числа округления.

Обновлять: Настоящий ответ на ваш вопрос заключается в использовании вами типа short int. При выполнении арифметики указателя (вычитания) между типизированными указателями C и C++ возвращают разницу в номер вещей, на которые указывает. Поскольку вы указываете на short int, размер которого составляет два байта, возвращаемое значение составляет половину ожидаемого.

С другой стороны, malloc всегда выделяет заданное количество байты, независимо от того, к какому результату вы приведете результат позже. Попробуй это:

    array=(short int*)malloc(sizeof(short int) * size);

malloc() будет иметь собственные накладные расходы.

Не говоря уже о том, что нет никакой гарантии, что 2 последовательных выделения с самого начала будут рядом друг с другом.

Во-первых, Malloc не дает никаких гарантий, что два последовательных вызова malloc вернут последовательные указатели.

Во-вторых, в зависимости от вашей конкретной архитектуры применяются разные правила выравнивания; иногда вы можете запросить один байт, но архитектура предпочитает распределение с 8- или 4-байтовыми интервалами.

В-третьих, malloc требует дополнительных затрат, чтобы запомнить размер выделенного блока и т. д.

Не делайте предположений о том, что делает malloc, помимо того, что написано в документации!

предположения рано или поздно доставят вам неприятности

BCS 10.01.2009 03:26

Если malloc возвращает что-либо, кроме нуля, тогда память, выделенная для него для вашей программы, имеет размер, который вы передали в malloc. Принятие разницы указателей между возвращаемыми значениями двух разностных вызовов malloc может иметь любое значение и не имеет ничего общего (ну очень мало) с размером блока первого выделенного блока.

Нет никаких гарантий, что два вызова malloc вернут блоки, точно упакованные вместе - на самом деле нет никаких гарантий относительно результата, за исключением того, что если он не NULL, он будет указывать на блок размером не менее запрошенного.

Внутри большинство маллоков содержат рабочие данные, которые помогают им управлять кучей. Например, эти 8 байтов могут содержать два указателя - один указывает на следующий блок, а другой указывает на предыдущий блок. Я не знаю, что это за 8 байтов, потому что вы не упомянули, на какой ОС вы работаете, но для malloc совершенно нормально использовать некоторую память для себя за кулисами.

Некоторые распределители (например, в Windows) предоставляют библиотечную функцию для определения размера блока по указателю, однако некоторые этого не делают, поскольку это довольно эзотерическая функция.

Выравнивание тоже в какой-то степени гарантировано, если я правильно помню.

user3458 10.01.2009 02:52

И вы гарантированно получите по меньшей мере столько, сколько вы просите, если вызов завершится успешно.

Max Lybbert 10.01.2009 11:17

Скорее всего, это будет размер и указатель на следующий или предыдущий блок.

Jonathan Leffler 11.01.2009 06:35

То, что возвращает malloc, зависит от реализации malloc и архитектуры. Как уже говорили другие, вы гарантированно получите как минимум запрошенный объем памяти или NULL. Вот почему иногда вы можете записать за конец массива и не получить ошибку сегментации. Это потому, что у вас действительно есть действительный доступ к этой памяти, вы просто не знали об этом.

malloc () обычно реализуется путем разделения доступной кучи на куски различного размера. В вашем случае malloc () возвращает 2 последовательных блока по 1024 (или 16) байтов. Указанное вами 8-байтовое пространство используется malloc () для бухгалтерской информации.

См. Примечания Дуга Ли malloc () impl здесь, чтобы понять, что происходит за кулисами: http://g.oswego.edu/dl/html/malloc.html

Ответ принят как подходящий

У вас ошибка. Вместо:

translatedArray=malloc(4*sizeof(short int));

У вас должно быть

translatedArray=malloc(4*sizeof(short int*));

Обратите внимание на отсутствующий указатель в вашем коде. Я подозреваю, что отсюда и проистекает ваше наблюдаемое поведение.


Также обратите внимание, что 0x804a420 - 0x804a018 = 1032, а не 516. Формула translatedArray[i] - translatedArray[i - 1] дает вам количество элементы (короткие целые числа или, проще говоря, коротких замыканий) между двумя адресами, а не количество байты.

нет, у меня такие же размеры блоков ... но я думаю, что вы правы насчет отсутствующего символа '*'

Quamis 10.01.2009 03:09

Я нашел это ... и проверьте ссылку ниже для получения дополнительной информации.

Распределение

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

необходимо = запрошено + 8

При необходимости <= 16, тогда ведро = 0

При необходимости> 16, тогда bucket = (log (необходимо) / log (2) с округлением до ближайшего целого числа) - 3

Размер каждого блока в списке, привязанном к сегменту, равен размеру блока = 2 сегмента + 4. Если список в сегменте равен нулю, память выделяется с помощью подпрограммы sbrk для добавления блоков в список. Если размер блока меньше страницы, то страница выделяется с помощью подпрограммы sbrk, и количество блоков, полученных путем деления размера блока на размер страницы, добавляется в список. Если размер блока равен или больше страницы, необходимая память выделяется с помощью подпрограммы sbrk, и один блок добавляется в список свободных для корзины. Если список свободных номеров не пуст, вызывающему абоненту возвращается блок во главе списка. Следующий блок в списке становится новым главой.

http://publib.boulder.ibm.com/infocenter/systems/index.jsp?topic=/com.ibm.aix.genprogc/doc/genprogc/sys_mem_alloc.htm

Обратите внимание, что ссылка предназначена для AIX, который может использовать совершенно другой malloc, чем glibc в Linux. Фактически, klibc, ulibc и любые другие библиотеки могут использовать разные методы. Большинство libc также позволяют программному обеспечению переопределять malloc по умолчанию.

Zan Lynx 05.06.2009 06:51

так что объем выделенной памяти, кажется, имеет 8 дополнительных байтов? Реализация malloc() в вашей системе, кажется, выделяет дополнительные байты для поддержки информации метаданных, например, размер раздела кучи, начальный адрес и т. д. Информацию.

Хотя это зависит от разных платформ. В моих системах X86 malloc() выделяет минимум 17 байтов, даже если я запрашиваю malloc(0).

int main(void) {
    int *p = malloc(0);
    if (p == NULL) {
        /* error handling */
    }
    printf("%d\n",p[-1]);/ *it prints 17 bytes */
    /* some code */
    return 0;
}

malloc () может выделять непрерывную память, но когда вы вызываете malloc () 2 раза и не можете ожидать, что выделенная память будет смежной, вычитая два указателя variabls ...

Однако выделенная память - это виртуальная память, которая является частью реализации ядра, а точнее управления памятью (VFS). Это не может повлиять на работу приложения.

Другие вопросы по теме