我已经分配了一个“数组” mystruct 的大小为 n ,如下所示:

if (NULL == (p = calloc(sizeof(struct mystruct) * n,1))) {
 /* handle error */
}

稍后,我只能访问 p ,并且不再拥有 n 。只有指针 p

才能确定数组的长度

我认为必须是可能的,因为 free(p)就是这样。我知道 malloc()会跟踪它分配了多少内存,这就是它知道长度的原因;也许有办法查询这些信息?有点像...

int length = askMallocLibraryHowMuchMemoryWasAlloced(p) / sizeof(mystruct)

我知道我应该重做代码,以便我知道 n ,但如果可能的话我宁愿不知道。有什么想法吗?

有帮助吗?

解决方案

不,如果不强烈依赖 malloc 的实现细节,就无法获取此信息。特别是, malloc 可以分配比您请求更多的字节(例如,为了特定存储器架构中的效率)。重新设计代码会更好,以便您明确地跟踪 n 。另一种方法是至少重新设计和更危险的方法(鉴于它是非标准的,滥用指针的语义,对于那些追随你的人来说将是一个维护噩梦):store malloc地址的长度 n ,后跟数组。然后分配:

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 ++。上帝帮助我们所有人。

其他提示

自己跟踪数组大小; free使用malloc链来释放分配的,它不一定与你请求的数组大小相同

只是为了确认以前的答案:仅通过研究指针,无法知道返回此指针的malloc分配了多少内存。

如果有效怎么办?

为什么这是不可能的一个例子。让我们假设一个带有假设函数的代码叫做get_size(void *),它返回为指针分配的内存:

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语言中,你总是可以编写自己的分配器,但是,当你只需要记住分配了多少内存时,可能会遇到太麻烦。

有些编译器提供了msize()或类似函数(_msize()等),让你可以做到这一点

我可以推荐一种可怕的方法吗?

按如下方式分配所有数组:

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

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

然后,您始终可以将数组转换为 int * 并访问第-1个元素。

确保 free 指针,而不是数组指针本身!

此外,这可能会导致可怕的错误,让你撕裂你的头发。也许你可以在API调用中包装alloc函数。

malloc将返回至少与您请求的一样大的内存块,但可能更大。因此,即使您可以查询块大小,也无法可靠地为您提供数组大小。因此,您只需修改代码即可自行跟踪。

对于指针数组,您可以使用以NULL结尾的数组。然后可以像使用字符串一样确定长度。在您的示例中,您可以使用结构属性来标记然后结束。当然,这取决于是否存在不能为NULL的成员。因此,假设您有一个属性名称,需要为数组中的每个结构设置,然后您可以通过以下方式查询大小:


int size;
struct mystruct *cur;

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

size = cur - myarray;

顺便说一句,你的例子应该是calloc(n,sizeof(struct mystruct))。

其他人讨论了普通c指针的限制和 malloc() stdlib.h 实现。某些实现提供了返回分配的块大小的扩展,该大小可能大于请求的大小。

如果必须具有此行为,则可以使用或编写专门的内存分配器。这个最简单的方法是在 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'd(或calloc'd)数据块的大小”。正如其他人所说:不,不是以标准的方式。

然而,有一些自定义malloc实现 - 例如 http://dmalloc.com/

我不知道一种方法,但我想它会解决在malloc内部的问题,这通常是一个非常非常糟糕的主意。

为什么你不能存储你分配的内存大小?

编辑:如果你知道你应该重做代码,那么你就知道了,好吧,做吧。是的,尝试对malloc进行轮询可能会快速而容易,但确定n肯定会减少混淆并加强设计。

您不能向malloc库询问块的大小的原因之一是,分配器通常会将请求的大小向上舍入以满足某些最小粒度要求(例如,16个字节)。因此,如果你要求5个字节,你将获得一个16的块。如果你取16并除以5,当你真的只分配一个元素时,你会得到三个元素。 malloc库需要额外的空间来跟踪您首先要求的字节数,因此最好自己跟踪它。

这是对我的排序程序的测试。它设置7个变量来保存浮点值,然后将它们分配给一个数组,用于查找最大值。

魔法在于对myMax的调用:

float mmax = myMax((float *)& arr,(int)sizeof(arr)/ sizeof(arr [0]));

那太神奇了,不是吗?

myMax需要一个float数组指针(float *),因此我使用& arr获取数组的地址,并将其转换为浮点指针。

myMax还希望数组中的元素数量为int。我通过使用sizeof()来获得该值,以给出数组的字节大小和数组的第一个元素,然后将总字节数除以每个元素中的字节数。 (我们不应该猜测或硬编码int的大小,因为它在某些系统上是2个字节,在某些系统上有4个像我的OS X Mac,在其他系统上可能是其他东西)。

注意:当您的数据可能包含不同数量的样本时,所有这一切都很重要。

这是测试代码:

#include <stdio.h>

float a, b, c, d, e, f, g;

float myMax(float *apa,int soa){
 int i;
 float max = apa[0];
 for(i=0; i< soa; i++){
  if (apa[i]>max){max=apa[i];}
  printf("on i=%d val is %0.2f max is %0.2f, soa=%d\n",i,apa[i],max,soa);
 }
 return max;
}

int main(void)
{
 a = 2.0;
 b = 1.0;
 c = 4.0;
 d = 3.0;
 e = 7.0;
 f = 9.0;
 g = 5.0;
 float arr[] = {a,b,c,d,e,f,g};

 float mmax = myMax((float *)&arr,(int) sizeof(arr)/sizeof(arr[0]));
 printf("mmax = %0.2f\n",mmax);

 return 0;
}

uClibc 中, MALLOC_SIZE 宏http://git.uclibc.org/uClibc/tree/libc/stdlib/malloc/malloc.h#n103"rel =“nofollow”> malloc.h

/* The size of a malloc allocation is stored in a size_t word
   MALLOC_HEADER_SIZE bytes prior to the start address of the allocation:

     +--------+---------+-------------------+
     | SIZE   |(unused) | allocation  ...   |
     +--------+---------+-------------------+
     ^ BASE             ^ ADDR
     ^ ADDR - MALLOC_HEADER_SIZE
*/

/* The amount of extra space used by the malloc header.  */
#define MALLOC_HEADER_SIZE          \
  (MALLOC_ALIGNMENT < sizeof (size_t)       \
   ? sizeof (size_t)                \
   : MALLOC_ALIGNMENT)

/* Set up the malloc header, and return the user address of a malloc block. */
#define MALLOC_SETUP(base, size)  \
  (MALLOC_SET_SIZE (base, size), (void *)((char *)base + MALLOC_HEADER_SIZE))
/* Set the size of a malloc allocation, given the base address.  */
#define MALLOC_SET_SIZE(base, size) (*(size_t *)(base) = (size))

/* Return base-address of a malloc allocation, given the user address.  */
#define MALLOC_BASE(addr)   ((void *)((char *)addr - MALLOC_HEADER_SIZE))
/* Return the size of a malloc allocation, given the user address. */
#define MALLOC_SIZE(addr)   (*(size_t *)MALLOC_BASE(addr))
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top