char *와 const char *의 차이점은 무엇입니까?


177

차이점은 무엇입니까

char* name

상수 문자열 리터럴을 가리키는

const char* name

C에서 " 상수 문자열 리터럴"은 무엇을 의미합니까 (C ++ 아님)
gbulmer

1
... char * name은 상수 문자열 리터럴을 가리 키도록 만들 수 있습니다
Iceman

모든 문자열 리터럴은 이론상 상수 엔터티에 있으므로 "일정한 문자열 리터럴"의 상수는 중복됩니다. 상수 또는 변경 가능하게 만들 수있는 변수의 내용입니다. "name"이 가리키는 문자의 내용을 변경하려고하면 "const"선언이 컴파일 타임 오류를 던집니다
Cupcake

단순 : "char * name"name은 char에 대한 포인터입니다. 즉 둘 다 여기에서 변경할 수 있습니다. "const char * name"name은 const char에 대한 포인터입니다.
akD

이 내용들을 오른쪽에서 왼쪽으로 읽으십시오.
Jiapeng Zhang

답변:


406

char*가변 문자 / 문자열에 대한 가변 포인터 입니다.

const char*불변의 문자 / 문자열에 대한 가변 포인터 입니다. 이 포인터가 가리키는 위치의 내용을 변경할 수 없습니다. 또한 컴파일러는 그렇게 할 때 오류 메시지를 표시해야합니다. 같은 이유에서 변환 에이 되지 않습니다.const char *char*

char* const이다 불변 (포인터가 다른 위치를 가리킬 수) 이지만 그 포인트가되는 위치의 내용을 변경할 수는 .

const char* const불변 문자 / 문자열에 대한 불변 포인터 입니다.


4
위에서 언급 한 후 변수를 사용하고 해당 변수에 대한 참조를 제공하면 혼동을 해결할 수 있습니다.
ankit.karwasra

3
@ ankit.karwasra, 당신은 또 하나를 놓쳤다 :char const *
Pacerier

변경 가능한 문자 / 문자열이있는 두 가지 옵션이 세분화 오류 메모리를 수행 할 수 있기 때문에 매우 위험하다고 생각합니다. 정말 똑똑하면 컴퓨터를 해킹 할 수 있습니다. 그렇기 때문에 컴파일러는 필자가 생각한 구현에서 항상 경고를 표시 한 것입니다
Daniel N.

1
뮤팅이 char *실행 중 세그먼트 화 오류를 일으키지 않습니까?
Divyanshu Maithani에서

1
따라서 const실수로 데이터를 잊어 버리고 변경하면 컴파일러에서 오류를 표시하려면 사용합니까?
회계사 م

43
char *name

당신이 name가리키는 문자와 그것을 가리키는 문자를 변경할 수 있습니다 .

const char* name

문자를 name가리키는 지점으로 변경할 수 있지만 해당 지점 의 문자를 수정할 수는 없습니다.
수정 : 포인터는 변경할 수 있지만 ( https://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx 를 가리키는 문자 는 변경할 수 없습니다 . "예제"참조 ). 이 경우 지정 자는 별표가 아닌에 적용됩니다 .nameconstchar

MSDN 페이지 및 http://en.cppreference.com/w/cpp/language/declarations 에 따르면 constbefore *는 decl 지정자 시퀀스의 일부이고 constafter *는 선언자의 일부입니다.
선언 지정자 시퀀스 뒤에 여러 선언자가 올 수 있으므로 as 및 as을 const char * c1, c2선언합니다 .c1const char *c2const char

편집하다:

주석에서 포인터가 문자열 리터럴을 가리킬 때 두 선언의 차이점에 대해 질문하는 것 같습니다.

이 경우 정의되지 않은 동작을 초래할 수 있는 지점 을 가리키는 문자를 수정 하면 안됩니다 . 문자열 리터럴은 읽기 전용 메모리 영역 (구현 정의)에 할당 될 수 있으며 사용자 프로그램은이를 수정해서는 안됩니다. 이렇게하면 정의되지 않은 동작이 발생합니다. name

따라서이 경우 (문자열 리터럴 사용)의 유일한 차이점은 두 번째 선언이 약간의 이점을 제공한다는 것입니다. 컴파일러는 두 번째 경우에서 문자열 리터럴을 수정하려고 할 때 일반적으로 경고를 표시합니다.

온라인 샘플 예 :

#include <string.h>
int main()
{
    char *str1 = "string Literal";
    const char *str2 = "string Literal";
    char source[] = "Sample string";

    strcpy(str1,source);    //No warning or error, just Undefined Behavior
    strcpy(str2,source);    //Compiler issues a warning

    return 0;
}

산출:

cc1 : 오류로 취급되는 경고
prog.c : 함수 'main'에서 :
prog.c : 9 : 오류 : 'strcpy'의 인수 1을 전달하면 포인터 대상 유형에서 한정자를 버립니다.

컴파일러는 두 번째 경우에는 경고하지만 첫 번째 경우에는 경고하지 않습니다.


고마워. 난 상수 문자열 리터럴과 혼합되었습니다, 그것은 다음과 같이 정의됩니다 : char * name = "String Literal"; "문자열 리터럴"변경은 정의되어 있지 않습니다.
Iceman

@ user1279782 : Err, 잠깐만! 여기서 문자열 리터럴을 가리키는 포인트에 대해 이야기하고 있습니까? 이 경우 어느 한 지점에서 문자를 수정하면 안되며name UB가 발생할 수 있습니다.
Alok

그렇습니다. 이 경우 char * name과 const char * name은 비슷하게 작동합니까?
Iceman

4
이 답변은 매우 모호하거나 잘못되었습니다. "이름이 가리키는 문자는 변경할 수 없지만 이름이 가리키는 문자는 수정할 수 있습니다."라고 해석합니다. : 포인터 자체를 수정할 수있는,하지만이 잘못 인을 가리키는하는 메모리 위치 수정 할 수 없다는으로 ideone.com/6lUY9s을 : 순수 C에 대한 대안으로 ideone.com/x3PcTP
shroudednight

1
@shroudednight : 정의되지 않은 동작에 대해 조금 더 배워야하며 다음과 구별해야합니다. 허용됨과 수행하지 말아야합니다. :)
Alok Save

16
char mystring[101] = "My sample string";
const char * constcharp = mystring; // (1)
char const * charconstp = mystring; // (2) the same as (1)
char * const charpconst = mystring; // (3)

constcharp++; // ok
charconstp++; // ok
charpconst++; // compile error

constcharp[3] = '\0'; // compile error
charconstp[3] = '\0'; // compile error
charpconst[3] = '\0'; // ok

// String literals
char * lcharp = "My string literal";
const char * lconstcharp = "My string literal";

lcharp[0] = 'X';      // Segmentation fault (crash) during run-time
lconstcharp[0] = 'X'; // compile error

// *not* a string literal
const char astr[101] = "My mutable string";
astr[0] = 'X';          // compile error
((char*)astr)[0] = 'X'; // ok

1
질문에 따라 "일정한 문자열 리터럴"을 가리키는 포인터는 없습니다.
caf

char *값을 변경하면 문자열 리터럴 (읽기 전용 메모리에 있음)을 수정하려고하기 때문에 분할 오류 가 발생한다는 점에 주목할 가치가 있습니다.
Divyanshu Maithani

10

어떤 경우에도 해당 문자열 리터럴에 대한 포인터가 char *또는 로 선언되는지 여부에 관계없이 문자열 리터럴을 수정할 수 없습니다 const char *.

그러나 포인터가 포인터이면 const char *지정된 값을 수정하려고하면 컴파일러에서 진단을 제공해야 하지만 포인터가 그렇지 않으면 컴파일러에서 진단을 제공해야합니다 char *.


1
"어떤 경우에도 ... [it]가 char * 또는 const char *로 선언되는지 여부에 관계없이 문자열 리터럴을 수정할 수는 없습니다."프로그래머가 시도해서는 안된다는 데 동의하지만 모든 C 컴파일러는 플랫폼은 코드를 거부하거나 런타임에 코드 실패를 준비합니까? 하나의 파일은 정의와 초기화를 가질 수 있고 다른 파일은 포함 extern ... name하고 가질 수 있다고 생각합니다 *name = 'X';. '적절한 운영 체제'에서는 실패 할 수 있지만 임베디드 시스템에서는 플랫폼 / 컴파일러에 특정한 작업을 수행 할 것으로 예상됩니다.
gbulmer

@gbulmer : 올바른 C 프로그램에서 문자열 리터럴을 수정할 수 없습니다. 시도하는 잘못된 C 프로그램은 여기도 없습니다.
caf

@gbulmer : 유용한 정의 중 하나는 C 언어 표준에 지정된 제약 조건을 위반하지 않는 프로그램입니다. 즉, 문자열 리터럴을 수정하는 프로그램은 널 포인터를 역 참조하거나 0으로 나누는 것과 같은 방식으로 올바르지 않습니다.
caf

caf-나는 그것이 당신이 의미하는 것이라고 생각했습니다. 그런 다음 "어떤 경우 에도 문자열 리터럴을 수정할 없습니다 "라는 말이 끝났습니다. "두 경우 모두 C 언어 표준에 의해 지정된 제약 조건이 다음과 무관하게 깨졌습니다. ... 컴파일러 나 런타임 시스템이 모든 경우에 표준 위반을 식별하는 것은 불가능합니다." 표준이 효과가 정의되지 않은 위치를 차지한다고 가정합니까?
gbulmer

1
표준이 어떤 식 으로든 주장 할 수 없을 때, 행동을 '정의되지 않은'것으로 정의하는 것이 정확히 올바른 경계이며 도움이되는 것 같습니다. 관계를 주장하기 위해 '올바른 C 프로그램' ' 널 (null) 포인터를 역 참조 할 수 없습니다 . 하지만 상관 없어요 나는 그것을하지 않을 것이며 그것을 '스콧 프리'로 도망 갈 것으로 예상 :-)
gbulmer

4

사례 1 :

char *str = "Hello";
str[0] = 'M'  //Warning may be issued by compiler, and will cause segmentation fault upon running the programme

위의 설정은 메모리의 읽기 전용으로 플래그가 지정된 프로그램의 이진 이미지에 하드 코딩 된 리터럴 값 "Hello"를 가리 키도록 str을 설정합니다.이 문자열 리터럴의 모든 변경은 불법이며 세그먼트 오류를 ​​발생시킵니다.

사례 2 :

const char *str = "Hello";
str[0] = 'M'  //Compile time error

사례 3 :

char str[] = "Hello";
str[0] = 'M'; // legal and change the str = "Mello".

2

원하는 경우 실제로 변경할 수있는 첫 번째는 변경할 수 없습니다. const정확성 에 대해 읽으십시오 (차이에 대한 좋은 가이드가 있습니다). 다시 char const * name지적 할 수없는 곳도 있습니다.


정확히 무엇을 바꿀 수 있습니까?
Antti Haapala

2

문제는 차이점은 무엇입니까

char *name

상수 문자열 리터럴을 가리키는

const char *cname

즉 주어진

char *name = "foo";

const char *cname = "foo";

둘 사이에는 큰 차이가 없으며 둘 다 올바른 것으로 볼 수 있습니다. C 코드의 오랜 유산으로 인해 문자열 리터럴의 유형은 char[]not const char[]이며 인수를 수정하지 않은 경우에도 char *대신 대신 허용 하는 이전 코드가 많이 const char *있습니다.

일반적으로 (2)의 주요 차이점이다 *cname또는 cname[n]유형을 평가한다 lvalues const char반면, *name또는 name[n]타입 lvalues으로 평가하게 char하고, 수정 lvalues . 할당 대상이 수정 가능한 lvalue가 아닌 경우 진단 메시지를 생성하려면 적합한 컴파일러가 필요합니다 . 유형의 lvalue에 할당 할 때 경고가 발생하지 않아도됩니다 char.

name[0] = 'x'; // no diagnostics *needed*
cname[0] = 'x'; // a conforming compiler *must* produce a diagnostics message

컴파일러는 두 경우 모두 컴파일을 중지 할 필요 가 없습니다 . 할당에 대한 경고 를 생성하는 것으로 충분합니다 cname[0]. 결과 프로그램이 올바른 프로그램이 아닙니다 . 구성의 동작은 정의되어 있지 않습니다 . 충돌하거나 더 나빠질 수 있으며 메모리에서 문자열 리터럴을 변경할 수 있습니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.