我怎样才能从C中的指针获取数组的大小?

我已经分配了一个大小为nmystruct的“数组”:

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

之后,我只能访问p ,不再有n 。 有没有一种方法来确定只给了指针p数组的长度?

我认为这一定是可能的,因为free(p)就是这样做的。 我知道malloc()跟踪它已经分配了多less内存,这就是为什么它知道长度; 也许有一种方法来查询这些信息? 就像是…

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

我知道我应该修改代码,以便知道n ,但是如果可能,我宁愿不要。 有任何想法吗?

不,如果不依赖于malloc的实现细节,就无法得到这些信息。 特别是, malloc可能会分配比您请求的更多的字节(例如,为了在特定内存体系结构中的效率)。 重新devise你的代码会更好,这样你可以明确地跟踪n 。 另一种方法至less是重新devise和更危险的方法(因为它是非标准的,滥用指针的语义,并将成为后面的维护者的噩梦):将长度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); 

编辑:只是扮演魔鬼的拥护者…我知道这些“解决scheme”都需要重新devise,但是让我们来玩吧。 当然,上面介绍的解决scheme只是一个(精心打包)结构的hacky实现。 你可以定义:

 typedef struct { unsigned int n; void *arr; } arrInfo; 

并传递arrInfo而不是原始的指针。

现在我们正在做饭。 但只要你在重新devise,为什么要在这里停下来呢? 你真正想要的是一个抽象的数据types(ADT)。 任何algorithm和数据结构类的介绍性文本都可以做到这一点。 ADT定义了数据types的公共接口,但隐藏了该数据types的实现。 因此,公开ADT的数组可能看起来像

 typedef void* arrayInfo; (arrayInfo)newArrayInfo(unsignd int n, unsigned int itemSize); (void)deleteArrayInfo(arrayInfo); (unsigned int)arrayLength(arrayInfo); (void*)arrayPtr(arrayInfo); ... 

换句话说,ADT是一种数据和行为封装的forms…换句话说,就像你可以用直接的C来进行面向对象的编程一样。除非你被困在一个平台上有一个C ++编译器,你也可以去整个猪,只是使用STL std::vector

在那里,我们已经谈到了一个关于C的简单问题,并以C ++结束。 上帝帮助我们。

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

只是为了确认以前的答案:没有办法知道,只是通过学习一个指针,一个malloc分配了多less内存,它返回了这个指针。

如果它有效?

为什么这是不可能的一个例子。 让我们设想一下带有假设函数的代码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经历了所有的麻烦以find大小(即以一种低效的方式),在这种情况下,它将返回一个在你的上下文中是错误的值。

结论

总是有办法避免这个问题,而在C中,你可以随时编写自己的分配器,但是当你需要记住分配了多less内存的时候,这也许是太麻烦了。

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

我可以推荐一个可怕的方法来做到这一点吗?

分配所有的数组,如下所示:

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

那么你总是可以把你的数组转换为int *并访问-1st元素。

一定要free该指针,而不是数组指针本身!

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

malloc将返回一块至less与你所要求的一样大的内存块,但可能更大。 所以,即使你可以查询块的大小,这不会可靠地给你你的数组大小。 所以你只需要修改你的代码来自己跟踪它。

对于指针数组,您可以使用以NULL结尾的数组。 长度然后可以像使用string那样确定。 在你的例子中,你可以使用一个结构属性来标记结束。 当然,这取决于是否有一个不能为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会最小化混淆并加强devise。

你不能要求malloc库有多大块的原因之一是分配器通常会将你的请求的大小加起来,以满足一些最小的粒度要求(例如16字节)。 所以,如果你要求5个字节,你会得到一个大小为16的块。 如果你把16和5分开,当你真的只分配一个时,你会得到三个元素。 malloc库需要额外的空间来跟踪你首先要求的字节数,所以最好自己跟踪一下。

这是我的sorting程序的testing。 它设置了7个variables来保存浮点值,然后将它们分配给一个用于查找最大值的数组。

神奇的是在对myMax的调用中:

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

那真是神奇,不是吗?

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

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

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

以下是testing代码:

 #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中有一个MALLOC_SIZEmacros:

 /* 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))