Нет, нет никакого способа получить эту информацию без зависимости сильно от деталей реализации malloc
. В частности, malloc
может выделить больше байтов, чем Вы запрашиваете (например, на эффективность в конкретной архитектуре памяти). Было бы намного лучше перепроектировать Ваш код так, чтобы Вы отслеживали n
явно. Альтернатива [по крайней мере 1 112] столько же модернизации и намного более опасный подход (учитывая, что это нестандартно, злоупотребляет семантикой указателей и будет кошмаром обслуживания для тех, которые приезжают после Вас): сохраните длину n
в адресе malloc'd, сопровождаемом массивом. Выделение тогда было бы:
void *p = calloc(sizeof(struct mystruct) * n + sizeof(unsigned long int),1));
*((unsigned long int*)p) = n;
n
теперь хранится в *((unsigned long int*)p)
, и запуск Вашего массива теперь
void *arr = p+sizeof(unsigned long int);
Редактирование: Только для игры защитника дьявола... Я знаю, что эти "решения" все требуют модернизаций, но давайте закончим его. Конечно, решением, представленным выше, является просто hacky реализация (хорошо упакованной) структуры. Вы могли бы также определить:
typedef struct {
unsigned int n;
void *arr;
} arrInfo;
и раздают arrInfo
с, а не необработанные указатели.
Теперь мы готовим. Но, пока Вы перепроектируете, почему остановка здесь? То, что Вы действительно хотите, является абстрактным типом данных (ADT). Любой вводный текст для алгоритмы и класс структур данных сделал бы это. ADT определяет открытый интерфейс типа данных, но скрывает реализацию того типа данных. Таким образом публично ADT для массива мог бы быть похожим
typedef void* arrayInfo;
(arrayInfo)newArrayInfo(unsignd int n, unsigned int itemSize);
(void)deleteArrayInfo(arrayInfo);
(unsigned int)arrayLength(arrayInfo);
(void*)arrayPtr(arrayInfo);
...
, Другими словами, ADT является формой данных и инкапсуляции поведения..., другими словами, это почти настолько близко, как можно добраться до Объектно-ориентированного программирования, использующего прямой C. Если Вы не застреваете на платформе, которая не имеет компилятора C++, Вы могли бы также пойти целый пожиратель ресурсов и просто использовать STL std::vector
.
Там, мы ответили на простой вопрос о C и закончили в C++. Бог помогает нам всем.
Одна из причин, что Вы не можете спросить malloc библиотеку, насколько большой блок, то, что средство выделения будет обычно окружать размер Вашего запроса для соответствия некоторому минимальному требованию гранулярности (например, 16 байтов). Таким образом, если Вы попросите 5 байтов, Вы получите блок размера 16 назад. Если бы необходимо было взять 16 и разделиться на 5, Вы получили бы три элемента, когда Вы действительно только выделили тот. Это заняло бы дополнительное место для malloc библиотеки для отслеживания то, сколько байтов Вы попросили во-первых, таким образом, лучше для Вас отслеживать это самих.
Я не знаю о пути, но я предположил бы, что он будет иметь дело со слонянием без дела во внутренностях malloc, которое обычно является очень, очень плохая идея.
, Почему случается так, что Вы не можете сохранить размер памяти, которую Вы выделили?
РЕДАКТИРОВАНИЕ: Если Вы знаете, что необходимо переделать код, таким образом, Вы знаете, что n, ну, в общем, делают это. Да это могло бы быть быстро и легко попытаться опросить malloc, но знающий n наверняка минимизирует беспорядок и усилит дизайн.
Другой обсудили пределы плоскости c указатели и stdlib.h
реализации malloc()
. Некоторые реализации обеспечивают расширения, которые возвращаются , выделил размер блока, который может быть больше, чем требуемый размер.
, Если Вы должны , имеют это поведение, можно использовать или записать специализированное средство выделения памяти. Эта самая простая вещь сделать реализовала бы обертку вокруг stdlib.h
функции. Некоторая вещь как:
void* my_malloc(size_t s); /* Calls malloc(s), and if successful stores
(p,s) in a list of handled blocks */
void my_free(void* p); /* Removes list entry and calls free(p) */
size_t my_block_size(void* p); /* Looks up p, and returns the stored size */
...
malloc возвратит блок памяти, по крайней мере, столь большой, как Вы запросили, но возможно больше. Таким образом, даже если бы Вы могли бы запросить размер блока, это надежно не дало бы Вам Ваш размер массива. Таким образом, необходимо будет просто изменить код для отслеживания его сами.
Я могу рекомендовать ужасному способу сделать это?
Выделяют все Ваши массивы следующим образом:
void *blockOfMem = malloc(sizeof(mystruct)*n + sizeof(int));
((int *)blockofMem)[0] = n;
mystruct *structs = (mystruct *)(((int *)blockOfMem) + 1);
Тогда можно всегда бросать массивы к int *
и получать доступ к-1-му элементу.
Быть уверенным free
, что указатель, а не сам указатель массива!
кроме того, это, вероятно, вызовет ужасные ошибки, которые оставят Вас отрывающий Ваши волосы. Возможно, можно обернуть выделение funcs в вызовы API или что-то.
Некоторые компиляторы обеспечивают msize () или подобные функции (_msize () и т.д.), которые позволяют Вам сделать точно это
Только подтвердить предыдущие ответы: нет никакого способа знать, только путем изучения указателя, сколько памяти было выделено malloc, который возвратил этот указатель.
Один пример того, почему это не возможно. Давайте вообразим код с гипотетической функцией названным get_size (пусто *), который возвращает память, выделенную для указателя:
typedef struct MyStructTag
{ /* etc. */ } MyStruct ;
void doSomething(MyStruct * p)
{
/* well... extract the memory allocated? */
size_t i = get_size(p) ;
initializeMyStructArray(p, i) ;
}
void doSomethingElse()
{
MyStruct * s = malloc(sizeof(MyStruct) * 10) ; /* Allocate 10 items */
doSomething(s) ;
}
, Но проблема этого подхода то, что в C можно играть с адресной арифметикой с указателями. Давайте перепишем doSomethingElse ():
void doSomethingElse()
{
MyStruct * s = malloc(sizeof(MyStruct) * 10) ; /* Allocate 10 items */
MyStruct * s2 = s + 5 ; /* s2 points to the 5th item */
doSomething(s2) ; /* Oops */
}
, Как get_size, как предполагается, работает, поскольку Вы отправили функции допустимый указатель, но не тот, возвращенный malloc. И даже если бы get_size прошел всю проблему для нахождения размера (т.е. неэффективным способом), это возвратило бы, в этом случае, значение, которое будет неправильно в контексте.
Там всегда является способами избежать этой проблемы, и в C, можно всегда писать собственное средство выделения, но снова, это - возможно, слишком много проблемы, когда все, в чем Вы нуждаетесь, должно помнить, сколько памяти было выделено.
отслеживайте размер массива сами; бесплатное использование malloc цепочка для освобождения блок , который был выделен, который не обязательно имеет тот же размер как массив, который Вы запросили
Для массива указателей можно использовать ЗАВЕРШЕННЫЙ ПУСТЫМ УКАЗАТЕЛЕМ массив. Длина может тогда определенный как он, сделан со строками. В Вашем примере можно, возможно, использовать атрибут структуры для маркировки тогда конца. Конечно, это зависит, если существует участник, который не может быть ПУСТЫМ. Так позволяет, говорят, что у Вас есть название атрибута, которое должно быть установлено для каждой структуры в Вашем массиве, которым можно тогда запросить размер:
int size;
struct mystruct *cur;
for (cur = myarray; cur->name != NULL; cur++)
;
size = cur - myarray;
Btw это должен быть calloc (n, sizeof (структура mystruct)) в Вашем примере.