2014-12-21 6 views
20

포인터와 함께 const를 사용하면 문제의 포인터를 사용하여 포인터를 역 참조함으로써 pointee를 수정할 수 없게됩니다. 하지만 포인터가 직접 가리키고 있지 않은 부분을 수정할 수없는 이유는 무엇입니까? 예를 들어C에서 const 및 포인터

:

int a = 3; 
const int* ptr = &a; 
*ptr = 5; 

가 컴파일되지 않습니다. 그런데 왜

*(ptr + 2) = 5; 

도 컴파일되지 않습니까? 나는 포인터가 무엇을 가리키고 있는지 바꾸지 않을 것이다.
그런 식으로 포인터를 사용하여 const를 사용하면 포인터가 참조하는 것 (포인터를 역 참조하는 것)뿐만 아니라 포인터를 사용하여 얻는 주소를 수정할 수 없다는 것을 말해야합니까?

나는이 예에서 할당되지 않은 메모리에 액세스하려고 시도하고 있음을 알고 있지만 이것은 단지 논의를위한 것입니다.

+0

그래서 컴파일러가 첫 번째'sizeof (int)'바이트 만'const'라고 가정하기를 기대 했습니까? 컴파일러는'ptr'로 접근 한 메모리 주소가 읽기 전용 주소 ("물리적으로"읽기 전용이거나 적어도'ptr '을 사용하는 함수의 "관점"에서 읽기 전용이라고 가정합니다. '). –

답변

25

ptr +2ptr과 동일한 유형 즉 단순히 const 개체에 대한 포인터입니다.

포인터 산술은 가리키는 대상이 모두 동일한 기본 유형의 배열이라고 가정합니다. 이 유형에는 const 인증이 포함됩니다.

+0

그래서 int + float = float와 비슷합니다. 그래서 const [type] * + some value = const [type] *, 맞습니까? – Root149

+0

@ Root149, 비슷합니다. 예. 포인터 유형에 정수 유형을 추가하면 동일한 포인터 유형이 다시 제공됩니다. –

+0

정상적인 정수형이 모든 것을 표현할 수있는 형식으로 승격되는 포인터 유형 감쇠 (배열을 포함하여 포인터가 포함될 때 모든 것이 포인터로 평탄화 됨) 만 있습니다. – Blindy

13

const에 의해 도입 된 수정 불가능 성은 const이 어디에 작성되는지에 따라 다릅니다.

당신이

const int * ptr = &a; 

(또는 int const * ptr = &a;은)는 const 그렇게 금지 대상에 기록 포인터를 사용하여 pointee을 말한다 작성하는 경우.

(료를이

int * const ptr = &a; 

을 썼다 OTOH, 경우 ptr을 수정할 수 있습니다.) 귀하의 경우에는

을 모든 대상에 쓰는 것은 금지되어 있습니다 포함.

이 (동등) 및 *ptrptr[0]을 포함하지만, 목적지 어드레스의 변형과 같은 *(ptr + 2) 또는 ptr[2] 관련된 또한 다.

+5

('const int *'와'int const *'는 const 포인터가 아니라 const와 같은 포인터입니다.) – Mat

+0

또한 "int * const ptr = & a;'"가 주어지면 "'* ptr = 5;'"그러나 "++ ptr'"가 아닙니다. 규칙에 대한 좋은 내용은 http://stackoverflow.com/questions/1143262/what-is-the-difference-between-const-int-const-int-const-int-const-의 첫 번째 줄에 나와 있습니다. 대답 - "뒤로 읽으십시오"- 아름답게 요약합니다. – frasnian

+0

@frasnian 이것은 본질적으로 제가 말한 것입니다.'++ ptr'는 "ptr을 수정할 수 없습니다"라고되어 있습니다. – glglgl

4

포인터도 배열로 사용할 수 있으므로 (argv 생각) 컴파일러는 포인터가 관련된 각 액세스를 제한합니다. 이 방법은 전체 배열이 읽기 전용입니다.

+0

글쎄, argv는 포인터 일 뿐이다. 왜냐하면 char * argv []는 char ** argv와 같기 때문에. 우리는 단지 배열의 환상을 만듭니다. – Root149

+0

@ Root149 배열은 포인터를 통해 액세스가 작동하기 때문에 액세스하는 데 별다른 차이가 없습니다. – glglgl

+1

@ Root149 : 그렇습니다. 그리고 그 환상으로 인해, 컴파일러는 포인터가 '환상'인지도 모릅니다. 'argv'와 같은 배열로 사용될 수 있기 때문에 모든 쓰기 액세스가 제한되어야합니다 ('ptr [0]'또는'ptr [100]'과 관계없이). –

3

표현의 유형에 대해 생각해 봅시다.

const int* ptr = &a; 

ptr의 유형은 const int*입니다.

따라서 *ptr 유형은 const int입니다. 수정할 수 없습니다.

(ptr + 2)의 유형은 여전히 ​​const int*이므로 *(ptr + 2)의 유형은 다시 수정할 수 없습니다. const int입니다.

9

다른 답변이 왜 작동하지 않는지에 대한 기술적 설명을 해 주지만 좀 더 일반적인 이유를 제시하고자합니다. 그것이 의미있는 유일한 것입니다.

컴파일러가 p + somethingp과 같은지 여부를 결정하는 일반적인 방법은 없습니다. 왜냐하면 something은 임의로 복잡 할 수 있기 때문입니다. 같은 규칙 "의 값은 변경 불가능한 있습니다 p에 의해 p + 0 지적하지만, 다른 값은 여전히 ​​수정 될 수있다"컴파일 타임에 확인할 수 없습니다 : 당신이 쓴 경우 상상 :

*(p + very complex expression) = ... 

는 컴파일러가 있는지 알아낼 수 있어야한다 very complex expression이 0입니까? 무엇 약

int s; 
scanf("%d", &s); 
*(p + s) = ... 

이 경우 컴파일러는 어떻게해야합니까?

여기서 합리적인 선택은 p을 통해 액세스 할 수있는 값을 수정할 수 없게 만드는 것입니다.

+0

이 문제는 컴파일러 의사 결정의 모호함으로 인한 것이 아닙니다. 이것은 유형 시스템의 규칙의 간단하고 정확한 결과입니다. –

+0

@ JamesT.Huggett : "컴파일러 의사 결정에서 애매한 점"이 무슨 뜻인지 모르겠습니다. 그 행동이 타이핑 규칙의 결과라는 것은 사실입니다. 제 대답은 타입 시스템의 규칙이 왜 이렇게 설계되었는지 설명하려고 시도합니다. –