10jobss   3년 전

예를 들어 d[2][2] 이차원 배열을 111로 초기화시키고자 할 때

1. fill(&d[0][0], &d[0][0]+sizeof(d), 111)

2. fill(&d[0][0], &d[1][2], 111)

3. fill(d, d+sizeof(d), 111)

세 가지 경우를 시도했습니다.

1번, 2번 경우는 의도한대로 작동하지만 3번의 경우 그렇지 않는데 이유가 궁금합니다.

(배열의 이름과 &d[0][0]가 동일하기 때문에 1번 경우와 3번 경우가 같다고 생각했습니다.)

2번 경우도 d[1][2]의 주소가 어떻게 참조되는지 이해가 안갑니다.

c++ 고수님들에게 도움 부탁드립니다.

lvalue   3년 전

1번과 3번은 틀린 코드입니다. sizeof(d)는 d 배열의 크기가 총 몇 바이트인지를 의미합니다. 그런데 포인터 연산을 할 때는 타입의 크기 단위로 움직입니다. (예를 들어 int d[4]; 라면 d+1은 d에서 4바이트 떨어진 메모리 위치를 의미합니다.) 그래서 d가 1바이트짜리 char타입이 아니라면 1번 코드는 배열의 크기를 넘어 참조됩니다.

2번에서 &d[1][2]는 참조 (de-reference)되어서는 안 되지만 가지고 있는 것은 허용되는 "past-the-end pointer"입니다. C++ 표준에 따르면 배열 인덱스 참조 후 다시 주소 연산자 (&)를 적용하면 참조하지 않는 것과 같게 하도록 되어 있습니다. 따라서 &d[1][2]는 d[1][2]의 원소를 참조하지 않습니다. 대신 컴파일러는 d[1] + 2과 같게끔 해석합니다.

3번은 std::fill에 전달되는 포인터의 타입을 보면 틀린 것을 쉽게 알 수 있습니다. d는 int[2][2], 즉 int들의 배열들의 배열입니다. 따라서 *d 는 int[2]형 값이 되고 int[2]형 값에 int형 값인 111을 assign할 수 없으므로 오류가 납니다.

10jobss   3년 전

@lvalue 설명 감사합니다!

댓글을 작성하려면 로그인해야 합니다.