Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get the size of an array from a pointer in C?

I've allocated an "array" of mystruct of size n like this:

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

Later on, I only have access to p, and no longer have n. Is there a way to determine the length of the array given just the pointer p?

I figure it must be possible, since free(p) does just that. I know malloc() keeps track of how much memory it has allocated, and that's why it knows the length; perhaps there is a way to query for this information? Something like...

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

I know I should just rework the code so that I know n, but I'd rather not if possible. Any ideas?

like image 352
Joel Avatar asked Oct 24 '08 07:10

Joel


People also ask

How do you find the size of a pointer array?

sizeof(list) / sizeof(*list) will always return the size of the array within the scope that defined it (so long as it's a c-style array of constant size).

Can you use sizeof on a pointer?

The code calls sizeof() on a malloced pointer type, which always returns the wordsize/8. This can produce an unexpected result if the programmer intended to determine how much memory has been allocated. The use of sizeof() on a pointer can sometimes generate useful information.

How do you find the size of an array without using sizeof operator?

&a + 1 => It points at the address after the end of the array. *(a+1) => Dereferencing to *(&a + 1) gives the address after the end of the last element. *(a+1)-a => Subtract the pointer to the first element to get the length of the array. Print the size.


1 Answers

No, there is no way to get this information without depending strongly on the implementation details of malloc. In particular, malloc may allocate more bytes than you request (e.g. for efficiency in a particular memory architecture). It would be much better to redesign your code so that you keep track of n explicitly. The alternative is at least as much redesign and a much more dangerous approach (given that it's non-standard, abuses the semantics of pointers, and will be a maintenance nightmare for those that come after you): store the lengthn at the malloc'd address, followed by the array. Allocation would then be:

void *p = calloc(sizeof(struct mystruct) * n + sizeof(unsigned long int),1)); *((unsigned long int*)p) = n; 

n is now stored at *((unsigned long int*)p) and the start of your array is now

void *arr = p+sizeof(unsigned long int); 

Edit: Just to play devil's advocate... I know that these "solutions" all require redesigns, but let's play it out. Of course, the solution presented above is just a hacky implementation of a (well-packed) struct. You might as well define:

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

and pass around arrInfos rather than raw pointers.

Now we're cooking. But as long as you're redesigning, why stop here? What you really want is an abstract data type (ADT). Any introductory text for an algorithms and data structures class would do it. An ADT defines the public interface of a data type but hides the implementation of that data type. Thus, publicly an ADT for an array might look like

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

In other words, an ADT is a form of data and behavior encapsulation... in other words, it's about as close as you can get to Object-Oriented Programming using straight C. Unless you're stuck on a platform that doesn't have a C++ compiler, you might as well go whole hog and just use an STL std::vector.

There, we've taken a simple question about C and ended up at C++. God help us all.

like image 151
Barry Wark Avatar answered Oct 19 '22 12:10

Barry Wark