const char * const 대 const char *?


110

C ++에 익숙해지기 위해 몇 가지 예제 프로그램을 실행 중이며 다음 질문에 직면했습니다. 먼저 다음은 예제 코드입니다.

void print_string(const char * the_string)
{
    cout << the_string << endl;
}

int main () {
    print_string("What's up?");
}

위 코드에서 print_string에 대한 매개 변수는 대신 const char * const the_string. 이것에 대해 어느 것이 더 정확할까요?

차이점은 하나는 상수 문자에 대한 포인터이고 다른 하나는 상수 문자에 대한 상수 포인터라는 것입니다. 하지만이 두 가지가 모두 작동하는 이유는 무엇입니까? 언제 관련이 있습니까?

답변:


244

후자는 the_string내부 수정을 방지합니다 print_string. 실제로 여기에서는 적절할 것이지만 아마도 장황함은 개발자를 미루 었습니다.

char* the_string: 포인트 char를 변경할 수 있고 the_string포인트를 수정할 수 있습니다 char.

const char* the_string: 나는 변경할 수 있습니다 charthe_string포인트를,하지만 난 수정할 수 없습니다 char그것을 지적하는.

char* const the_string: 나는 변경할 수 없습니다 charthe_string포인트를,하지만 난 수정할 수 있습니다 char그것을 지적하는.

const char* const the_string: char어느 the_string지점 을 가리키는 지 변경할 수 없으며 , 가리키는 지점을 수정할 수도 없습니다 char.


11
마지막 문장은 +1. Const-correctness는 장황하지만 그만한 가치가 있습니다.
mskfisher

6
@Xeo : 당신의 형태는 의미를 완전히 바꾸는 것에서 하나의 전치이기 때문에 훨씬 더 혼란 스럽습니다. 완전히 반대편에 const char *있기 때문에 훨씬 좋습니다 const.
R .. GitHub STOP HELPING ICE

7
@R .. : 글쎄, 적어도 나에게는 그렇지 않습니다. 오른쪽에서 왼쪽으로 읽으면 "const char에 대한 포인터"가 표시됩니다. 제게는 그런 식으로 기분이 나아졌습니다.
Xeo

6
C 유형은 왼쪽에서 오른쪽이 아니라 안쪽에서 바깥쪽으로 읽혀지기 때문에 자신을 속이고 있습니다. :-)
R .. GitHub STOP HELPING ICE

11
좀 내가 분명히에만이를 이해하지 못하는 사람이야 당황 해요 ...하지만 "는 문자의 차이 무엇 그것을 가리키는"와 "숯불 그것을 가리키는"는?
부족

138
  1. 변경 가능한 문자에 대한 변경 가능한 포인터

    char *p;
  2. 상수 문자에 대한 가변 포인터

    const char *p;
  3. 가변 문자에 대한 상수 포인터

    char * const p; 
  4. 상수 문자에 대한 상수 포인터

    const char * const p;

:이 안 const char* p; --> constant pointer to mutable characterchar *const p; --> mutable pointer to constant character
PnotNP

2
@NulledPointer 아니요. C ++ 선언은 오른쪽에서 왼쪽으로 구성됩니다. 따라서 const char * p"p는 문자 상수에 대한 포인터"또는 James가 올바르게 언급 한 상수 문자에 대한 가변 포인터로 읽을 수 있습니다 . 두 번째 :)와 동일합니다.
Samidamaru 2015

28

const char * const포인터와 포인터가 가리키는 데이터는 모두 const입니다!

const char *포인터가 가리키는 데이터 const 임을 의미 합니다 . 그러나 포인터 자체는 const가 아닙니다.

예.

const char *p = "Nawaz";
p[2] = 'S'; //error, changing the const data!
p="Sarfaraz"; //okay, changing the non-const pointer. 

const char * const p = "Nawaz";
p[2] = 'S'; //error, changing the const data!
p="Sarfaraz"; //error, changing the const pointer. 

20

(이것이 오래되었다는 것을 알고 있지만 어쨌든 공유하고 싶었습니다.)

Thomas Matthews의 대답에 대해 자세히 설명하고 싶었습니다. C 유형 선언의 오른쪽-왼쪽 규칙은 거의 말합니다.

이것은 몇 가지 예를 통해 가장 잘 설명됩니다.

예 1

  • 식별자에서 시작해 오른쪽으로 갈 수 없어 왼쪽으로

    const char* const foo
                ^^^^^

    foo는 상수입니다 ...

  • 계속 왼쪽

    const char* const foo
              ^

    foo는 ...에 대한 상수 포인터입니다 .

  • 계속 왼쪽

    const char* const foo
          ^^^^

    foo는 char에 대한 상수 포인터입니다 .

  • 계속 왼쪽

    const char* const foo
    ^^^^^

    foo는 char 상수에 대한 상수 포인터입니다 (Complete!)

예 2

  • 식별자에서 시작해 오른쪽으로 갈 수 없어 왼쪽으로

    char* const foo
          ^^^^^

    foo는 상수입니다 ...

  • 계속 왼쪽

    char* const foo
        ^

    foo는 ...에 대한 상수 포인터입니다 .

  • 계속 왼쪽

    char* const foo
    ^^^^

    foo는 char에 대한 상수 포인터입니다 (Complete!)

예제 1337

  • 식별자에서 시작하지만 이제 바로 갈 수 있습니다!

    const char* const* (*foo[8])()
                            ^^^

    foo는 8 ...

  • 괄호를 치면 더 이상 오른쪽으로 갈 수 없어 왼쪽으로

    const char* const* (*foo[8])()
                        ^

    foo는 ...에 대한 8 포인터 의 배열입니다 .

  • 괄호 안에 완료되었습니다. 이제 바로 갈 수 있습니다.

    const char* const* (*foo[8])()
                                ^^

    foo는 ... 를 반환 하는 함수에 대한 8 개의 포인터 배열입니다 .

  • 더 이상 오른쪽으로 이동하지 않고 왼쪽으로 이동

    const char* const* (*foo[8])()
                     ^

    foo는 ...에 대한 포인터를 반환 하는 함수에 대한 8 개의 포인터 배열입니다 .

  • 계속 왼쪽

    const char* const* (*foo[8])()
                ^^^^^

    foo는 상수에 대한 포인터를 반환하는 함수에 대한 8 개의 포인터 배열입니다 .

  • 계속 왼쪽

    const char* const* (*foo[8])()
              ^

    foo는 상수 포인터에 대한 포인터를 반환하는 함수에 대한 8 포인터의 배열입니다 .

  • 계속 왼쪽

    const char* const* (*foo[8])()
          ^^^^

    foo는 char 에 대한 상수 포인터에 대한 포인터를 반환하는 함수에 대한 8 포인터의 배열입니다 .

  • 계속 왼쪽

    const char* const* (*foo[8])()
    ^^^^^

    foo는 char 상수 에 대한 상수 포인터에 대한 포인터를 반환하는 함수에 대한 8 포인터의 배열입니다 (Complete!)

추가 설명 : http://www.unixwiz.net/techtips/reading-cdecl.html


CMIIW, const char * const foo는 char const * const foo와 동일해야합니까?
luochenhuan

@luochenhuan 예, 실제로 그렇습니다.
Garrett

12

많은 사람들이 유형 지정자를 오른쪽에서 왼쪽으로 읽는 것이 좋습니다.

const char * // Pointer to a `char` that is constant, it can't be changed.
const char * const // A const pointer to const data.

두 형식 모두에서 포인터는 상수 또는 읽기 전용 데이터를 가리 킵니다.

두 번째 형식에서는 포인터를 변경할 수 없습니다. 포인터는 항상 같은 위치를 가리 킵니다.


3

차이점은 const프로그래머가 포인터가 가리키는 메서드 내에서 추가 기능없이 변경할 수 있다는 것입니다. 예를 들면 :

 void print_string(const char * the_string)
 {
    cout << the_string << endl;
    //....
    the_string = another_string();
    //....

 }

서명이 다음과 같으면 대신 불법입니다. void print_string(const char * const the_string)

많은 프로그래머는 (대부분의 시나리오에서) 추가 const키워드를 너무 장황하게 느끼고 의미 상 정확하더라도 생략합니다.


2

후자의 경우 처음에는 포인터와 문자를 모두 수정하지 않도록 보장합니다. 내용이 변경되지 않을뿐 아니라 포인터를 주위로 이동할 수 있습니다.


Ahh 그래서 최종 const없이 나는 실제로 완전히 다른 문자열을 가리 키도록 포인터를 설정할 수 있습니까?
pict

예, 최종 const 없이는 매개 변수 포인터를 사용하여 포인터 산술로 일부 반복을 수행 할 수 있습니다. 해당 const가 있으면 해당 매개 변수의 사본 인 자체 포인터를 만들어야합니다.
Jesus Ramos

2

둘 다 작동하지 않을 이유가 없습니다. 모든 print_string()것은 값을 인쇄하는 것입니다. 수정하려고하지 않습니다.

표시 인수를 const로 수정하지 않는 함수를 만드는 것이 좋습니다. 장점은 변경할 수없는 (또는 변경하고 싶지 않은) 변수를 오류없이 이러한 함수에 전달할 수 있다는 것입니다.

정확한 구문에 관한 한, 함수에 전달하기에 "안전한"인수 유형을 나타내려고합니다.


2

함수가 & * the_string 또는 ** the_string과 같은 인수로 호출되지 않기 때문에 거의 관련이 없다고 생각합니다. 포인터 자체는 값 유형 인수이므로 수정하더라도 함수를 호출하는 데 사용 된 복사본을 변경하지 않을 것입니다. 보여 주신 버전은 문자열이 변경되지 않도록 보장하며이 경우 충분하다고 생각합니다.


2

const char *포인터를 사용하여 가리키는 내용을 변경할 수 없음을 의미합니다. 하지만 다른 것을 가리 키도록 포인터를 변경할 수 있습니다.

치다:

const char * promptTextWithDefault(const char * text)
{
    if ((text == NULL) || (*text == '\0'))
        text = "C>";
    return text;
}

매개 변수는 const char에 const char *대한 상수 가 아닌 포인터이므로 상수 문자열과 같은 다른 값 으로 변경할 수 있습니다 . 그러나 실수로 작성 *text = '\0'하면 컴파일 오류가 발생합니다.

틀림없이, 매개 변수가 가리키는 것을 변경하지 않으려면 매개 변수를 만들 수 const char * const text있지만 그렇게하는 것은 일반적이지 않습니다. 일반적으로 함수가 매개 변수에 전달 된 값을 변경할 수 있도록 허용합니다 (매개 변수를 값으로 전달하기 때문에 변경 사항은 호출자에게 영향을주지 않습니다).

BTW : char const *잘못 읽는 경우가 많기 때문에 피하는 것이 좋습니다 . const char *이는과 같은 의미이지만 너무 많은 사람들이이를 의미로 읽습니다 char * const.


와! 저는 저 const char *와 서명의 차이점을 알아 내려고했습니다. char const *당신이 BTW를 표현한 방식이 정말 도움이되었습니다!
세이지

1

거의 모든 다른 답변은 정확하지만 이것의 한 가지 측면을 놓치고 있습니다 const. 함수 선언에서 매개 변수에 대해 extra를 사용 하면 컴파일러는 본질적으로이를 무시합니다. 잠시 동안 포인터가되는 예제의 복잡성을 무시하고 int.

void foo(const int x);

다음과 같은 기능을 선언합니다.

void foo(int x);

함수 정의 에서만 추가 const의미가 있습니다.

void foo(const int x) {
    // do something with x here, but you cannot change it
}

이 정의는 위의 선언 중 하나와 호환됩니다. 발신자는 상관하지 않는 x것입니다 const호출 사이트에서 관련이없는의 구현 세부 사항입니다 --that.

데이터에 대한 const포인터 가있는 경우 const동일한 규칙이 적용됩니다.

// these declarations are equivalent
void print_string(const char * const the_string);
void print_string(const char * the_string);

// In this definition, you cannot change the value of the pointer within the
// body of the function.  It's essentially a const local variable.
void print_string(const char * const the_string) {
    cout << the_string << endl;
    the_string = nullptr;  // COMPILER ERROR HERE
}

// In this definition, you can change the value of the pointer (but you 
// still can't change the data it's pointed to).  And even if you change
// the_string, that has no effect outside this function.
void print_string(const char * the_string) {
    cout << the_string << endl;
    the_string = nullptr;  // OK, but not observable outside this func
}

const매개 변수가 포인터인지 여부에 관계없이 매개 변수를 만들 수있는 경우에도 C ++ 프로그래머는 거의 없습니다 .


"컴파일러는 본질적으로이를 무시합니다."항상 사실은 아닙니다. Visual C ++ 2015는 const정의에서 함수 매개 변수에 추가 를 추가 하지만 선언 에는 추가하지 않으면 경고를 생성 합니다.
raymai97

@ raymai97 : 2015 년 컴파일러의 버그라고 생각하지만 2015 년은 테스트 할 수 없습니다. 일부 표준 전문가와의 대화에 따르면 예상되는 행동 인 2017 년에 설명한대로 작업합니다.
Adrian McCarthy

-1

둘 사이의 차이점은 char *가 임의의 포인터를 가리킬 수 있다는 것입니다. 대조적으로 Const char *는 실행 파일의 DATA 섹션에 정의 된 상수를 가리 킵니다. 따라서 const char * 문자열의 문자 값을 수정할 수 없습니다.


char *와 const char *의 차이점을 묻지 않습니다. 나는 const char *와 const char * const 사이에 묻고있다
pict

이 대답은 틀 렸습니다. A const char*는 원하는 곳을 가리킬 수 있습니다.
Cubic
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.