문제

이것은 어리석은 질문처럼 들릴지 모르지만 여전히 C를 배우고 있습니다. :)

저는 K & R (Structs)의 6 장에서 일하고 있으며 지금 까지이 책을 통해 큰 성공을 거두었습니다. 나는 Structs와 함께 많은 일을하기로 결정했기 때문에 챕터 초반에 Point and Rect 예제로 많은 작업을 수행했습니다. 내가 시도하고 싶은 것 중 하나는 canonrect 기능 (2 판, p 131) 포인터를 통해 작업하므로 반환 void.

나는이 일을했지만, 너희들이 나를 도울 수 있기를 바라고있는 딸꾹질을 만났다. 나는 원했다 canonRect 임시 사각형 객체를 만들려면 변경 사항을 수행 한 다음 포인터를 임시 사각형으로 통과시켜 코드를 단순화하십시오.

그러나 내가 그렇게한다면, 직장은 변하지 않습니다. 대신, 나는 내가 통과 한 직장의 들판을 수동으로 다시 채우는 것을 발견했다.

코드는 다음과 같습니다.

#include <stdio.h>

#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))

struct point {
    int x;
    int y;
};

struct rect {
    struct point lowerLeft;
    struct point upperRight;
};

// canonicalize coordinates of rectangle
void canonRect(struct rect *r);

int main(void) {
    struct point p1, p2;
    struct rect r;

    p1.x = 10;
    p1.y = 10;
    p2.x = 20;
    p2.y = 40;
    r.lowerLeft = p2; // note that I'm inverting my points intentionally
    r.upperRight = p1;

    printf("Rectangle, lower left: %d, %d; upper right: %d %d\n\n", 
        r.lowerLeft.x, r.lowerLeft.y, r.upperRight.x, r.upperRight.y);

    // can't pass a pointer, only a reference. 
    // (Passing pointers results in illegal indirection compile time errors)
    canonRect(&r); 
    printf("Rectangle, lower left: %d, %d; upper right: %d %d\n\n", 
        r.lowerLeft.x, r.lowerLeft.y, r.upperRight.x, r.upperRight.y);    
}

void canonRect(struct rect *r) {
    struct rect temp;
    temp.lowerLeft.x = min(r->lowerLeft.x, r->upperRight.x);
    temp.lowerLeft.y = min(r->lowerLeft.y, r->upperRight.y);
    temp.upperRight.x = max(r->lowerLeft.x, r->upperRight.x);
    temp.upperRight.y = max(r->lowerLeft.y, r->upperRight.y);

    r = &temp; // doesn't work; my passed-in rect remains the same

    // I wind up doing the following instead, to reassign all 
    // the members of my passed-in rect
    //r->lowerLeft = temp.lowerLeft;
    //r->upperRight = temp.upperRight;
}

그래서 다음은 다음과 같습니다.

  1. r = &temp; 작동하지? (나 생각한다 포인터 대신 참조를 전달하기 때문입니다. 참고 문헌은 수정할 수 없지만 포인터는?)
  2. 포인터를 전달하려고하면 불법 간접 컴파일 시간 오류를받을 수있는 이유 canonRect? (즉, 내가 있다면 canonRect(*r); 안에 main().)

나는 이미 #1에 대한 답을 알고 있다고 생각하지만, #2는 저를 당황합니다. 나는 포인터를 전달하는 것이 합법적이라고 생각했습니다.

어쨌든 ... C Newb를 용서 해주세요.

도움이 되었습니까?

해결책

나는 당신이하고 싶은 것이 이것이라고 생각합니다.

void canonRect(struct rect *r) {
    struct rect temp;
    temp.lowerLeft.x = min(r->lowerLeft.x, r->upperRight.x);
    temp.lowerLeft.y = min(r->lowerLeft.y, r->upperRight.y);
    temp.upperRight.x = max(r->lowerLeft.x, r->upperRight.x);
    temp.upperRight.y = max(r->lowerLeft.y, r->upperRight.y);

    *r = temp; 
}

위의 코드에서 당신은 type rect의 type rect to temp 인 *r을 설정합니다.

RE 1 : R을 가리키는 R을 변경하려면 포인터에 대한 포인터를 사용해야합니다. 그것이 당신이 정말로 당신이 원하는 것인지 (위의 참조, 그것은 실제로 원하는 것이 아닙니다) 힙에 무언가를 가리켜 야합니다. 'New'또는 Malloc으로 생성되지 않은 것으로 가리키면 범위가 떨어지고 더 이상 해당 변수에 사용되지 않는 메모리를 가리키게됩니다.

코드가 r = & temp와 함께 작동하지 않는 이유는 무엇입니까?

r은 rect* type이기 때문입니다. 즉, R은 메모리의 메모리가 낙인을 포함하는 메모리 주소를 보유하는 변수임을 의미합니다. R이 가리키는 것을 변경하면 괜찮지 만 변수로 전달 된 것을 변경하지는 않습니다.

RE 2 : * 유형 선언에 사용되지 않은 경우 DeReference 단독 연산자입니다. 이것은 포인터의 주소 내부에있는 것을 조회한다는 것을 의미합니다. 그래서 *r을지나 가면 당신은 전혀 포인터를 전달하지 않습니다. R은 포인터가 아니기 때문에 얼굴이 유효하지 않습니다.

다른 팁

또한 당신의 변수 'struct rec temp'가 그 방법이 CanonRect가 끝나 자마자 범위를 벗어날 것이라는 점을 지적 할 가치가 있습니다.

'Dereference'연산자를 혼란스럽게하는 것 같습니다 (*) '연산자의 주소와 함께 (&).

당신이 쓸 때 &r, R의 주소를 가져오고 R에 대한 포인터를 반환합니다 (포인터는 변수의 메모리 주소 일뿐입니다). 그래서 당신은 실제로 기능에 포인터를 전달하고 있습니다.

당신이 쓸 때 *r, 당신은 r에서 r을 시도하고 있습니다. r이 포인터 인 경우 r이 가리키는 값을 반환합니다. 그러나 R은 포인터가 아니라 직장이므로 오류가 발생합니다.

더 혼란스럽게 만들기 위해 * 포인터 변수를 선언 할 때 문자도 사용됩니다. 이 기능 선언에서 :

void canonRect(struct rect *r) {

r A에 대한 포인터로 선언됩니다 struct rect. 이것은 사용과 완전히 다릅니다 * 이와 같이:

canonRect(*r); 

두 경우 모두 * 캐릭터는 완전히 다른 것을 의미합니다.

첫째, K & R C에는 "참조"개념이 없으며 포인터 만 있습니다. 그만큼 & 연산자는 "주소를 가져 가라"를 의미합니다.


둘째, r 안에 cannonRect() 로컬 변수입니다 ~ 아니다 그만큼 r 안에 main(). 지역의 위치 변경 r 포인트는 영향을 미치지 않습니다 r 호출 루틴에서.


마지막으로, 이미 현지인이 언급했듯이 struct rect 스택에 할당되며 가까운 브레이스에서 경향이 없습니다.

매개 변수가 (개념적으로) 함수로 전달 될 수있는 다양한 방법을 읽을 수 있습니다. C입니다 콜 바이 값, 포인터를 직장으로 전달할 때는 포인터의 사본을 전달합니다. 함수가 값 r에 대한 변경 사항은 (간접적으로 아님) 발신자에게 보이지 않습니다.

기능이 발신자에게 새로운 구조물을 제공하려면 두 가지 방법이 있습니다. 1. rect를 반환 할 수 있습니다.

첫 번째 방법은 더 자연 스럽습니다.

struct rect* canonRect(struct rect* r)
{
  struct rect* cr = (struct rect*) malloc(sizeof(struct rect));
  ...
  return cr;
}

두 번째 방법은 다음과 같습니다.

void canonRect(struct rect** r)
{
  *r = (struct rect*) malloc(sizeof(struct rect));
}

그리고 발신자는 다음을 사용합니다.

   canonRect(&r);

그러나 발신자는 원래의 포인터를 잃어 버리고 스트러크를 누출하지 않도록주의해야합니다.

어떤 기술을 사용하든 Malloc을 사용하여 힙의 새 구조물에 대한 메모리를 할당해야합니다. 함수가 반환 될 때 메모리가 유효하지 않기 때문에 구조물을 선언하여 스택의 공간을 할당 할 수 없습니다.

2. CanOnRect를 포인터로 전달하려고하면 왜 불법 간접 컴파일 시간 오류를받을 수 있습니까? (즉, CanOnRect (*r); main ()에있는 경우).

왜냐하면 그것은 목적이 아니기 때문입니다 바늘.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top