2012-01-27 2 views
12

두 번 void 포인터를 사용하려고하는데 사용법에 대해 조금 혼란 스럽습니다. void ** 배열을 포함하는 struct이 있습니다.void ** 포인터를 올바르게 사용하는 방법은 무엇입니까?

struct Thing{ 
    void ** array; 
}; 

struct Thing * c = malloc (sizeof(struct Thing)); 
c->array = malloc(10 * sizeof(void *)); 

그래서 각 포인터에 다른 객체를 할당하고 값을 검색하려고 할 경우

// Option 1 
*(c->array + index) = (void *) some_object_ptr; 

// Option 2 
c->array[index] = (void *) some_object_ptr; 

후, 나는 각 셀이 아닌 some_object_ptr를 가리키는 (void *) item을 제공합니다 다른 기능을 가지고 .

내가 some_object_ptr가 가리키는 값을 검색하려면,
는 어떻게해야

function return type is 'void *' and takes argument 'void *' 
// Option 3 
return (void**) item 

// Option 4 
return *((void**)item)? 

이상한 것은 내가 배열을 사용하는 경우 배열 첨자 방법은 내가 옵션 4를 사용할 수 없다는 것입니다, 유일한 옵션 3; 그리고 내가 *(c->array + index)을 사용할 때 나는 opt.4 만 사용할 수있었습니다. 하지 opt.3. ..

아무에게도 이것에 대해 말해 줄 수 있습니까? 내가 잘못된 가정을하고 있다면, 제발 저를 시정 해 주시겠습니까?

+1

이 왜'무효 *'로 작업하는 자리 확보/패배의 조심? 더 나쁜,'무효 **'? – Kevin

+10

아마도 그 사람이 필요로할까요? –

+0

또한 옵션 3과 4는 같지 않습니다. 3은'void **'를 반환하고 4는'void *'를 반환합니다. 'item'이란 정확히 무엇입니까? – Kevin

답변

18

void **은 지정되지 않은 유형의 메모리 포인터에 대한 포인터입니다. 한 번만 역 참조 할 수 있습니다 (void *을 역 참조 할 수 없기 때문에). 그러나, 그 점을 제외하고는 기본적으로 다른 포인터 유형과 같습니다. 도움이된다면, int *과 같은 방식으로 생각하십시오.

따라서, 특정 상황에서, 우리는이 : 그것은 array[0]에 해당하기 때문에 *array는, 첫 번째 요소에 대한 포인터 동안

void** array; 
int arrayLen = 10; 
array = (void**)malloc(arrayLen * sizeof(void*)); 

some_type_t* some_object_ptr;  
// The following two assignment are equivalent since in C, 
// array[index] <=> *(array + index) 
array[index] = (void*)some_object_ptr; 
*(array + index) = (void*)some_object_ptr; 

그런 다음 array이 전체 배열에 대한 포인터입니다.

+0

셀을 가리키는 인수로 void * 받아 다음 반환 할 때 사용해야합니다. 3 또는 opt 4? 나는 조금 혼란 스럽다. –

+0

당신이 돌아가고 싶은 것에 달려있다. 배열 또는 배열의 첫 번째 요소를 반환 하시겠습니까. 만약 당신이'int * array;'를 가지고 있다면'return array;'또는'return array [0];'을 할 것인가? 이것은 여기에서 동일합니다. –

+0

저는 셀에있는 것을 반환하고 싶습니다. 나는 다른 객체를 가리키는 void 포인터이고 반환하는 부분은 다른 기능을 가지고 있기 때문에 인덱스를 모르는 것이라고 생각합니다. 대신 void 포인터가있는 셀을 가리키는 void * item이 주어진다. –

1

void*void**과 관련된 사실은 중요하지 않습니다. 포인터 연산은 여전히 ​​정상적으로 작동하므로 작성한 두 옵션이 모두 정확합니다. 여기

은 예입니다 : 그것은 당신이 포인터가 넣을 수 있습니다 void* 이래로

struct Thing 
{ 
    void ** array; 
}; 

struct Object 
{ 
    int i; 
    char c; 
}; 

int main() 
{ 

    struct Thing * c = malloc (sizeof(struct Thing)); 
    c->array = malloc(10 * sizeof(void*)); 

    struct Object * o = malloc (sizeof(struct Object)); 
    o->i = 2; o->c = 'a'; 

    *(c->array + 2) = o; 

    printf("Object: i = %d, c = %c\n", ((Object*)c->array[2])->i, ((Object*)c->array[2])->c); 

    free(o); 
    free(c->array); 
    free(c); 
    return 0; 
} 

무엇이든, 단지 그것을 사용하기 전에 원래의 타입으로 캐스팅을 잊지 마세요)

+2

malloc()의 반환 값을 캐스팅 할 필요가 없다. C 표준은 void *가 * 모든 * 포인터 유형과 호환된다는 것을 명시 적으로 말합니다. 리누스 토발즈 (Lius Torvalds)와 같은 존경받는 C 프로그래머와 GNU와 같은 기업은이 캐스팅에 반대하며 가독성을 떨어 뜨리기 때문에 나쁜 관행이라고 말합니다. –

+0

또한 포인터 연산은 정수와 동일하지 않습니다. AFAIK GCC는 void *를 바이트 ptr로 가정하고, 예를 들어 32 비트 시스템에서 int는 4 바이트이므로 (int *) ptr + 1은 (void *) ptr과 다른 메모리 주소를 제공합니다 + 1 것이다. –

+0

죄송합니다. C로 코딩 할 때도 Microsoft Visual Studio에서 작업하곤합니다. 컴파일러에서는 반환 값을 변환하지 않고 malloc을 작성할 수 없습니다 ... 내 대답을 편집했습니다. – LihO

2

한 빠른 힌트에 대한 포인터 : 당신이 그것을 캐스팅하는 경우, 당신은 아마 뭔가 잘못하고 있습니다.

질문 사항. item이 (가) 귀하의 문제는 아닙니까? 첫 번째 부분에서는 이미 배열에있는 멤버에 액세스하는 방법을 이미 살펴 보았습니다. 당신은 인덱스 포인터의 주소를해야하는 경우

void *get_item(Thing *c, int index) 
{ 
    return *(c->array + index); // or return c->array[index]; 
} 

: 두 번째 부분에서

void **get_item_cell(Thing *c, int index) 
{ 
    return c->array + index; // or return &c->array[index]; 
} 

당신이 (+ 옵션) 포인터 역 참조하지 않습니다, 또는 당신은 단순히 그것을 사용할 수 배열 결과를 자동으로 역 참조하기 때문에 배열 결과의 주소를 가져옵니다.


편집 : 나는 이제 네가 원하는 것을 알고 있다고 생각한다. 당신은 위의 내 두 번째와 유사한 기능을 가지고 있지만, 그것은이다 :

void *get_item_cell(Thing *c, int index) 
{ 
    return (void *)(c->array + index); 
} 

당신은 값이이 함수에서 반환 역 참조를 원하고, 개체에 액세스 할 수 있습니다. 이 경우 옵션 4 만 안전하게 사용할 수 있습니다. 색인이 없으므로 다른 셀로 이동할 수 없습니다 (배열의 끝에 있거나 시작 부분에 알 수 없기 때문에 추가 또는 빼기가 필요하지 않습니다). 위의 함수의 실수는 해결할 수 있습니다. void **으로 캐스팅 한 후 역 참조 : *(void **)item. 그러면 void *이 표시됩니다. 이 셀에서 가리키는 객체에 액세스하려면 올바른 유형으로 캐스팅해야합니다 (some_object_ptr *obj = *(void**)item).

+0

오, 그래서 돌아 오는 부분은 다른 함수에서 인덱스를 알지 못한다. * item은 셀 배열을 가리킨다. –

+0

당신이하고 싶은 것에 대한 나의 이해 만. pointee의 주소 (배열에있는 객체)가 있고 배열의 색인이나 셀로 돌아가려면 각 셀을 반복해야하고 pointee가 다음과 같은 객체인지 확인해야합니다. 원하는 정보를 입력 한 다음 관련 정보를 반환하십시오. 이것이 당신이 원하는 것이라면, 나는 그것을 나의 대답에 추가 할 수 있습니다. – vhallac

-1

올마이티 푸시!

any_type x ; 
void * v = * (void * *) & x ; 

올마이티 풀!

void * v ; 
any_type x = * (any_type *) & v ; 

+0

'void * v = * (void **) & x;'는'void * v = & x;'를 넘어서서 어떤 목적을합니까? '& x'의 캐스트와 참조 해제는 아무 것도하지 않습니다.A * 메모리 주소 *에는 시작하는 형식이 없습니다. –

+0

"*'any_type' *"확실합니까? 포인터 유형 만 말하고 싶습니다. – alk

+0

@ DavidC.Rankin : C의 한계로 인해 함수 포인터의 값을'void' 포인터에 할당 할 수없는 이런 식으로 주위를 속일 수 있습니다. – alk