2012-12-05 2 views
2

나는 사람 이름의 소개를 단순히 인쇄하는 다음 코드를 가지고 있습니다. C 포인터 참조

#include <stdio.h> 
#include <stdlib.h> 

typedef struct { 
    char* firstname; 
    char* lastname; 
}Person; 

void intro(void *person){ 
    printf("The person you are looking for is %s %s\n", ((Person *)person)->firstname, ((Person *)person)->lastname); 
} 

int main() 
{ 
    Person *a = NULL; 
    a = (Person *)malloc(sizeof(Person)); 

    char *first = NULL, *last = NULL; 
    first = (char *)malloc(sizeof(char)*20); 
    strncpy(first,"Bob", 20); 
    last = (char *)malloc(sizeof(char)*20); 
    strncpy(last,"Newmonson", 20) 
    a->firstname = first; 
    a->lastname = last; 

    intro(a); 

    return 0; 
} 

The person you are looking for is Bob Newmonson

그러나 내가 GDB의 첫 번째 시도를 열고 난을 찾을 라인 (10)에 침입하면 intro(&a)-intro(a)

The person you are looking for is �@ Newmonson

을 생산 변화의 출력을 생성합니다 주소는 person=0x601010입니다. 이름과 성은 모두 내가 기대할 수있는 위치에 저장됩니다 (0x04006b90x4006bd).

나는 GDB를 실행하여 변경된 내용을 intro(&a)으로 변경했습니다. person의 주소는 이제 0x7fffffffffdd38이며, 이름은 0x601010이고 성은 0x4006db입니다.

아무도 무슨 일이 일어나고 있는지, 왜 두 번째 테스트에서성에 대한 적절한 주소에 계속 액세스 할 수 있는지 설명 할 수 있습니까?

편집 : 모든 사람으로

이 그것을 void * 내가 포함되지 않은이 코드의 나사 부분에 대한이었다에 대해 물어 유지할 것으로 보인다.

+4

참고 :'첫번째 = (숯불 *) malloc을 (를 sizeof (숯불) * 20); first = "Bob"; '당신이하고 있다고 생각하는 것을하지 않습니다. –

+1

또한'intro()'와 함께 작업하기를 희망하는 유일한 것이'Person *'일 때'int *()'를'void *'라고 취하는 이유는 무엇입니까? –

+0

@MichaelBurr 연습을 위해'void * '를 사용하고 싶었지만 대신이 문제가 발생했습니다. – Blackninja543

답변

4

a은 이미 Person 구조체에 대한 포인터이므로, 따라서 intro(&a)은 해당 포인터에 대한 포인터를 전달하지만 intro()은 포인터를 Person에 대한 포인터로 처리합니다.

또한 intro()이 Person에서 작동하도록하려면 void *이 아닌 Person * 인수를 선언해야합니다.

+0

'void *'비트는 처음에는이 문제와 관련이 없었기 때문에 우연히 일치했습니다. – Blackninja543

+0

@ Blackninja543 : 사실,'void *'가 중요했습니다. 함수가 더 적절하게 선언 되었으면, 컴파일러는'intro (& a) '를 사용할 때 포인터 타입 불일치를 경고했을 것입니다. 'void *'를 사용하는 것은 피해야한다. 뭔가 잘못되었다는 큰 붉은 깃발이 필요하다. –

3

포인터 변수 a 안에있는 주소는 a이 차지하는 실제 메모리 위치의 주소와 다릅니다.

그리고 주소는 0x601010과 같이 "낮은"메모리 주소이며 일반적으로 힙 어딘가에 있습니다. 0x7fffffffffdd38과 같은 주소는 매우 "높은"주소이며 일반적으로 스택에 있습니다. 따라서 &a은 스택에 변수 a의 실제 주소를 제공하고 포인터 변수 변수 a에 저장된 값 0x601010이 아닌 함수에 해당 값을 전달하고 할당 된 메모리 버퍼의 첫 번째 주소를 나타냅니다. malloc.

intro이 유형 Person의 구조에 포인트를 가정 포인터를 기대 : 모든

0

첫째 : intro(&a)를 사용하여 당신에게 예상치 못한 결과를 제공하는 이유

/* allocate space for 20 characters and make 'first' point to that space. */ 
first = (char *)malloc(sizeof(char)*20); 
/* now make 'first' point to the string Bob. Leak the memory that was allocated before. */ 
first = "Bob"; 
/* Rinse, lather, repeat. */ 
last = (char *)malloc(sizeof(char)*20); 
last = "Newmonson"; 

지금 설명합니다. Person에 대한 포인터를 만든 다음 공간을 할당합니다. intro(a)를 호출

Person에 대한 포인터가 다음 Person에 대한 포인터로 취급하고 모두가 잘 소개시켜하기 void에 대한 포인터로 전달됩니다. intro(&a)를 호출

그러나 a주소 소요.이 다시 introPerson에 대한 포인터로 취급하려고하지만, 무엇 당신이 통과 한 것은 포인터에 대한 포인터이기 때문에 문제가 해결되지 않습니다 통과 a Person. 오렌지를 먹는다고 생각하는 함수에 토마토를 전달하고 있습니다. 맛있는 오렌지 주스 대신에 맛있는 토마토 주스가 아침 식사에 제공 될 때 매우 행복하지는 않을지라도, 둘 다 과일이고, 당신은 주스를 얻을 것입니다.

intro(&a)을 호출하면 이름이 맹 글링되지만 성이 인쇄되는 이유는 궁금한 점이 있습니다. 그 이유는 단순한 행운 때문입니다. 성이 표시된 문자열이 메모리의 올바른 위치에 있었던 것입니다. .

0

이 시도 :

#include <stdio.h> 
#include <stdlib.h> 

typedef struct { 
    char* firstname; 
    char* lastname; 
}Person; 

void intro(Person *person){ 
    printf("The person you are looking for is %s %s\n", (person)->firstname, (person)->lastname); 
} 

int main() 
{ 
    Person *a = NULL; 
    char *first = NULL, *last = NULL; 
    a = (Person *)malloc(sizeof(Person)); 


    first = (char *)malloc(sizeof(char)*20); 
    first = "Bob"; 
    last = (char *)malloc(sizeof(char)*20); 
    last = "Newmonson"; 
    a->firstname = first; 
    a->lastname = last; 

    intro(a); 

    return 0; 
} 

그것이 도움이되기를 바랍니다 ...

+0

'Person *'을'Person *'으로 캐스팅하는 이유는 무엇입니까? –

+0

나는 불필요한 것을 알고 있지만 컴파일러를 진정시키기 위해 좋은 습관을 가지고있다. P – omi

+0

다시 오시나요? 그게 무슨 뜻인지는 모르겠다. –