C의 포인터에서 배열의 크기를 어떻게 얻을 수 있습니까?
다음 과 같은 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
명시 적으로 추적 할 수 있도록 코드를 다시 디자인하는 것이 훨씬 낫습니다 . 대안은 적어도 많은 재 설계 및 훨씬 더 위험한 방식으로 (그것이 표준이 아닌 있다고 주어진 남용에게 포인터의 의미, 그리고 후에 오는 것들에 대한 유지 보수 악몽이 될 것입니다) : 길이를 저장 n
다음 malloc에 주소 뒤에 배열이 있습니다. 할당은 다음과 같습니다.
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);
편집 : 악마의 옹호자 역할을하기 위해 ...이 "솔루션"은 모두 재 설계가 필요하다는 것을 알고 있지만 실행 해 보겠습니다. 물론 위에 제시된 솔루션은 (잘 포장 된) 구조체의 해키 구현 일뿐입니다. 다음을 정의 할 수도 있습니다.
typedef struct {
unsigned int n;
void *arr;
} arrInfo;
arrInfo
원시 포인터가 아닌 s를 전달합니다 .
이제 우리는 요리하고 있습니다. 그러나 재 설계하는 한 여기서 멈추는 이유는 무엇입니까? 정말로 원하는 것은 추상 데이터 유형 (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 */
}
함수에 유효한 포인터를 보냈지 만 malloc에 의해 반환 된 포인터가 아닌 경우 get_size가 작동하는 방식입니다. 그리고 get_size가 크기를 찾기 위해 모든 문제를 겪더라도 (즉, 비효율적 인 방식으로),이 경우 컨텍스트에서 잘못된 값을 반환합니다.
결론
항상이 문제를 피할 수있는 방법이 있으며, C에서는 항상 자신의 할당자를 작성할 수 있지만 다시 한 번, 할당 된 메모리 양을 기억하는 것이 필요한 경우 너무 많은 문제가 될 수 있습니다.
일부 컴파일러는 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은 최소한 요청한만큼 큰 메모리 블록을 반환하지만 더 클 수도 있습니다. 따라서 블록 크기를 쿼리 할 수 있다고해도 어레이 크기를 안정적으로 제공하지 않습니다. 따라서 직접 추적하기 위해 코드를 수정해야합니다.
포인터 배열의 경우 NULL로 끝나는 배열을 사용할 수 있습니다. 그런 다음 길이는 문자열로 수행되는 것처럼 결정할 수 있습니다. 귀하의 예에서 구조 속성을 사용하여 표시하고 끝낼 수 있습니다. 물론 NULL이 될 수없는 멤버가 있는지 여부에 따라 다릅니다. 따라서 배열의 모든 구조체에 대해 설정해야하는 속성 이름이 있다고 가정하면 다음과 같이 크기를 쿼리 할 수 있습니다.
int size;
struct mystruct *cur;
for (cur = myarray; cur->name != NULL; cur++)
;
size = cur - myarray;
Btw 귀하의 예제에서는 calloc (n, sizeof (struct mystruct))이어야합니다.
기타 일반 C 포인터의 한계와 논의한 stdlib.h
의 구현 malloc()
. 일부 구현 은 요청 된 크기보다 클 수있는 할당 된 블록 크기 를 반환하는 확장을 제공 합니다.
If you must have this behavior you can use or write a specialized memory allocator. This simplest thing to do would be implementing a wrapper around the stdlib.h
functions. Some thing like:
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 */
...
really your question is - "can I find out the size of a malloc'd (or calloc'd) data block". And as others have said: no, not in a standard way.
However there are custom malloc implementations that do it - for example http://dmalloc.com/
I'm not aware of a way, but I would imagine it would deal with mucking around in malloc's internals which is generally a very, very bad idea.
Why is it that you can't store the size of memory you allocated?
EDIT: If you know that you should rework the code so you know n, well, do it. Yes it might be quick and easy to try to poll malloc but knowing n for sure would minimize confusion and strengthen the design.
One of the reasons that you can't ask the malloc library how big a block is, is that the allocator will usually round up the size of your request to meet some minimum granularity requirement (for example, 16 bytes). So if you ask for 5 bytes, you'll get a block of size 16 back. If you were to take 16 and divide by 5, you would get three elements when you really only allocated one. It would take extra space for the malloc library to keep track of how many bytes you asked for in the first place, so it's best for you to keep track of that yourself.
This is a test of my sort routine. It sets up 7 variables to hold float values, then assigns them to an array, which is used to find the max value.
The magic is in the call to myMax:
float mmax = myMax((float *)&arr,(int) sizeof(arr)/sizeof(arr[0]));
And that was magical, wasn't it?
myMax expects a float array pointer (float *) so I use &arr to get the address of the array, and cast it as a float pointer.
myMax also expects the number of elements in the array as an int. I get that value by using sizeof() to give me byte sizes of the array and the first element of the array, then divide the total bytes by the number of bytes in each element. (we should not guess or hard code the size of an int because it's 2 bytes on some system and 4 on some like my OS X Mac, and could be something else on others).
NOTE:All this is important when your data may have a varying number of samples.
Here's the test code:
#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;
}
In uClibc, there is a MALLOC_SIZE
macro in 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))
참고URL : https://stackoverflow.com/questions/232691/how-can-i-get-the-size-of-an-array-from-a-pointer-in-c
'code' 카테고리의 다른 글
Oracle의 기존 테이블에 자동 증가 기본 키 추가 (0) | 2020.11.15 |
---|---|
Node.js 스크립트에 대한 적절한 해시 뱅 (0) | 2020.11.15 |
C #에서 File과 FileInfo의 차이점은 무엇입니까? (0) | 2020.11.15 |
MSBuild 파일에 대한 표준 파일 확장자가 있습니까? (0) | 2020.11.15 |
Rabbitmq 또는 Gearman-작업 대기열 선택 (0) | 2020.11.15 |