소년코딩

07.11 - 문자열 기호 상수 (C-style string symbolic constants)

'07.06 - C-style strings' 포스트에서 C 스타일 문자열을 만들고 초기화하는 방법에 대해 배웠다.

#include <iostream>

int main()
{
    char myName[] = "Alex";
    std::cout << myName;

    return 0;
}

C++은 또한 포인터를 사용해서 C 스타일 문자열 기호 상수를 만드는 방법도 지원한다.

#include <iostream>

int main()
{
    const char *myName = "Alex";
    std::cout << myName;

    return 0;
}

위의 두 프로그램은 같은 결과를 생성하고 운영하지만, C++은 이들 프로그램에 대한 메모리 할당을 약간 다르게 한다.

고정 배열의 경우 프로그램은 길이가 5인 고정 배열에 메모리를 할당하고 "Alex\0" 문자열로 해당 메모리를 초기화한다. 배열에 대해 메모리가 구체적으로 할당되었으므로 배열의 내용을 자유롭게 변경할 수 있다. 배열 자체는 일반 지역 변수로 처리되므로 배열이 범위를 벗어나면 배열에서 사용하는 메모리가 다른 용도로 사용할 수 있다.

기호 상수의 경우, 컴파일러가 이를 어떻게 처리하는지 구현에 따라 정의된다. 일반적으로 컴파일러는 문자열 "Alex\0"을 읽기 전용 메모리 어딘가에 배치한 다음 가리키는 포인터를 설정한다. 이 메모리는 읽기 전용이므로 문자열이 const인지 확인하는 것이 좋다.

최적화를 위해 여러 문자열을 리터럴을 단일 값으로 통합할 수 있다.

const char* name1 = "Alex";
const char* name2 = "Alex"

값이 같은 두 개의 다른 문자열 리터럴이다. 컴파일러는 이들을 단일 공유 문자열 리터럴로 결합할 수 있으며, name1name2는 같은 주소를 가리킨다. 따라서, name1이 const가 아닌 경우 name1을 변경하면 name2에 영향을 줄 수 있다.

또한, 이 방법으로 선언된 문자열은 프로그램 수명 내내 지속되므로 범위(scope) 지정 문제에 대해 걱정할 필요가 없다.

const char* getName()
{
    return "Alex";
}

위의 코드에서 getName()은 C 스타일 문자열 "Alex"에 대한 포인터를 반환한다. getName()이 종료될 때 "Alex"는 범위를 벗어나지 않으므로 호출자가 계속 성공적으로 접근할 수 있다.

요약하면 나중에 수정할 수 있는 문자열 변수가 필요한 경우 문자 배열을 사용하자. 읽기 전용 문자열 리터럴이 필요한 경우에는 문자열 리터럴에 대한 const 포인터를 사용하자.


std::cout and char pointers

이 시점에서 std::cout이 다른 유형의 포인터를 처리하는 방식에 대해 흥미로울 것이다.

#include <iostream>

int main()
{
    int nArray[5] = { 9, 7, 5, 3, 1 };
    char cArray[] = "Hello!";
    const char *name = "Alex";

    std::cout << nArray << '\n'; // nArray will decay to type int*
    std::cout << cArray << '\n'; // cArray will decay to type char*
    std::cout << name << '\n'; // name is already type char*

    return 0;
}
003AF738
Hello!
Alex

왜 int형 배열은 주소를 출력했지만, 문자 배열은 문자열을 출력했을까?

그 답은 std::cout가 의도에 대해 몇가지 가정을 한다는 것이다. 비문자 포인터(non-char pointer)를 포인터의 내용(포인터가 보유하고 있는 주소)을 출력한다. 그러나 char* 또는 const char* 유형의 객체를 전달하면 문자열을 출력한다고 가정한다. 결과적으로, 포인터의 값을 출력하는 대신에 지시된 문자열을 출력한다.

이것은 예상치 못한 결과를 초래할 수 있다.

#include <iostream>

int main()
{
    char c = 'Q';
    std::cout << &c;

    return 0;
}

이 경우, 프로그래머는 변수 c의 주소를 출력하려고 한다. 그러나 &c는 char* 타입을 가지고 있으므로 std:cout는 이것을 문자열로 출력하려고 한다. 다음과 같이 출력된다.

Q╠╠╠╠╜╡4; ¿ ■ A

왜 그럴까? &c를 문자열이라고 가정한다. 그래서 'Q'를 출력한 다음 쓰레기값을 출력한다. 널 종결자를 가진 어떤 메모리를 만날때까지 출력하는 것이다. 변수 c 다음 메모리 내용에 따라 달라질 수 있다.


cpp 번역: 이 포스트의 원문은 http://www.learncpp.com/cpp-tutorial/6-8-pointers-and-arrays/ 입니다. 입니다.

댓글 로드 중…

블로그 정보

소년코딩 - 소년코딩

소년코딩, 자바스크립트, C++, 물리, 게임 코딩 이야기

최근에 게시된 이야기