Как я могу получить размер массива от указателя в C?

66
задан Ryan Stein 30 December 2013 в 16:49
поделиться

10 ответов

Нет, нет никакого способа получить эту информацию без зависимости сильно от деталей реализации 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++. Бог помогает нам всем.

52
ответ дан Ryan Stein 24 November 2019 в 15:05
поделиться

Одна из причин, что Вы не можете спросить malloc библиотеку, насколько большой блок, то, что средство выделения будет обычно окружать размер Вашего запроса для соответствия некоторому минимальному требованию гранулярности (например, 16 байтов). Таким образом, если Вы попросите 5 байтов, Вы получите блок размера 16 назад. Если бы необходимо было взять 16 и разделиться на 5, Вы получили бы три элемента, когда Вы действительно только выделили тот. Это заняло бы дополнительное место для malloc библиотеки для отслеживания то, сколько байтов Вы попросили во-первых, таким образом, лучше для Вас отслеживать это самих.

1
ответ дан Greg Hewgill 24 November 2019 в 15:05
поделиться

Я не знаю о пути, но я предположил бы, что он будет иметь дело со слонянием без дела во внутренностях malloc, которое обычно является очень, очень плохая идея.

, Почему случается так, что Вы не можете сохранить размер памяти, которую Вы выделили?

РЕДАКТИРОВАНИЕ: Если Вы знаете, что необходимо переделать код, таким образом, Вы знаете, что n, ну, в общем, делают это. Да это могло бы быть быстро и легко попытаться опросить malloc, но знающий n наверняка минимизирует беспорядок и усилит дизайн.

1
ответ дан Bob Somers 24 November 2019 в 15:05
поделиться

Другой обсудили пределы плоскости 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 */
...
2
ответ дан dmckee 24 November 2019 в 15:05
поделиться

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

2
ответ дан David Arno 24 November 2019 в 15:05
поделиться

Я могу рекомендовать ужасному способу сделать это?

Выделяют все Ваши массивы следующим образом:

void *blockOfMem = malloc(sizeof(mystruct)*n + sizeof(int));

((int *)blockofMem)[0] = n;
mystruct *structs = (mystruct *)(((int *)blockOfMem) + 1);

Тогда можно всегда бросать массивы к int * и получать доступ к-1-му элементу.

Быть уверенным free, что указатель, а не сам указатель массива!

кроме того, это, вероятно, вызовет ужасные ошибки, которые оставят Вас отрывающий Ваши волосы. Возможно, можно обернуть выделение funcs в вызовы API или что-то.

4
ответ дан Claudiu 24 November 2019 в 15:05
поделиться

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

8
ответ дан dmityugov 24 November 2019 в 15:05
поделиться

Только подтвердить предыдущие ответы: нет никакого способа знать, только путем изучения указателя, сколько памяти было выделено 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, можно всегда писать собственное средство выделения, но снова, это - возможно, слишком много проблемы, когда все, в чем Вы нуждаетесь, должно помнить, сколько памяти было выделено.

9
ответ дан paercebal 24 November 2019 в 15:05
поделиться

отслеживайте размер массива сами; бесплатное использование malloc цепочка для освобождения блок , который был выделен, который не обязательно имеет тот же размер как массив, который Вы запросили

16
ответ дан Steven A. Lowe 24 November 2019 в 15:05
поделиться

Для массива указателей можно использовать ЗАВЕРШЕННЫЙ ПУСТЫМ УКАЗАТЕЛЕМ массив. Длина может тогда определенный как он, сделан со строками. В Вашем примере можно, возможно, использовать атрибут структуры для маркировки тогда конца. Конечно, это зависит, если существует участник, который не может быть ПУСТЫМ. Так позволяет, говорят, что у Вас есть название атрибута, которое должно быть установлено для каждой структуры в Вашем массиве, которым можно тогда запросить размер:


int size;
struct mystruct *cur;

for (cur = myarray; cur->name != NULL; cur++)
    ;

size = cur - myarray;

Btw это должен быть calloc (n, sizeof (структура mystruct)) в Вашем примере.

2
ответ дан quinmars 24 November 2019 в 15:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: