[C++] 문자열의 저장

sookyeong·2023년 3월 13일
0

strcpy의 필요성

배열을 복사하려면
for문으로 각 요소를 돌아주면서 하나하나 복사를 진행해야 한다.

문자열도 배열의 일종이기 때문에 (문자의 배열)
문자열을 복사하려면 for문으로 한 문자씩 복사해주어야한다.
한방에 *dest = *src 이런거 불가 (이런건 메모리 하나 단위의 복사 시 유효)

strcpy함수는 이러한 기능을 구현해놓은 함수다.

배열로 선언한 문자열에 입력값 저장 시

char str[100] 이렇게 크기를 명시해서 문자열 선언 후
scanf("%s", str) 이렇게 복사해주면 입력한 문자열 끝에 널문자가 자동으로 삽입되기 때문에
거기서 문자열이 끝나게 된다.

즉, 콘솔에서 choco를 입력 후 strlen(str)으로 문자열 길이를 확인하면 5가 나온다.
한편, sizeof(str)을 하면 배정된 전체 메모리의 크기가 나오므로 여전히 100이 나온다.

포인터로 선언한 문자열에 입력값 저장 시

정확히는 char형 포인터를 선언한 뒤
동적 할당한 메모리 공간에 문자열을 저장하고 그 포인터를 앞서 선언한 포인터에 할당해주는 방식이다.

char* strptr;
char namestr[100];
cin >> namestr;
strptr = new char[strlen(namestr) + 1];
strcpy(strptr, namestr);

여기서 namestr은 문자열 배열임
[□□□□□□□□□□□□□] 이렇게 걍 하나란 말임
여기다가 문자열을 받은 다음에 이걸 매개변수로 넘겨주면
namestr 본체의 주소가 가는거임 (배열의 이름은 해당 배열의 주소이므로)
따라서 namestr에 담긴 값이 변경되면 다른 애들도 고대로 변경되어버리는거임
값 복사가 아니라 주소가 넘어가는거니까

반면 strptr를 따로 만들어서 namestr을 strcpy해주면
namestr은 일종의 임시 바구니가 되는거임
namestr에다가 값을 잠시 받아놓고
그 길이+1(널) 만큼 새로운 메모리 공간을 할당한 후
그곳에다 namestr에 받아뒀던 값을 저장한 뒤 그 포인터를 strptr에 할당하는거임

예제 ObjArr의 경우

Person parr[3];
char* strptr;
char namestr[100];

for(int i=0; i<3; i++)
{
    cin >> namestr;   // 일단 바구니에 받음
    strptr = new char[strlen(namestr) + 1];     // 필요한 만큼의 메모리 공간을 동적 할당
    strcpy(strptr, namestr);        // 할당한 공간에 바구니에 저장된 값을 복사
    parr[i].SetPersonInfo(strptr);     // 할당한 공간의 주소를 넘겨줌
}

루프1에서는 strptr가 힙1을 가리킨 채로 매개변수로 넘어가는거고
루프2에서는 힙2, 루프3에서는 힙3이 각각 넘어가는거임
결국 다른 주소가 넘어감으로써 얘네가 덮어씌워지는 일은 일어나지 않는거임
(매 루프마다 strptr이 참조하는 메모리가 달라지므로)

포인터 문자열을 선언과 동시에 초기화할 시

char *str = "안녕" 이렇게 선언한 경우의 문자열은 읽기 전용 문자열(쓰기 불가)이 되기 때문에
const char*로 받아줘야됨 (이런걸 상수 형태의 문자열이라고 부름)

반면 동적 할당한 힙을 가리키는 char 포인터는 읽기 전용 문자열을 가리키고 있는게 아니기 때문에
char*로 받을 수 있음

예제 ObjPtrArr의 경우

ObjPtrArr 예제에서는 Person(const char* myname, int myage) 생성자를 통해 변수를 초기화 하고 있는데
이 함수에서 myname을 바구니로 사용해서 name에 문자열을 복사하기 때문에 namestr을 넘겨줘도
전체 객체가 마지막 값으로 덮어씌워지지 않는거임
따라서 strcpy 부분을 없앤 다음 name=myname 해버리면 이전 예제에서와 마찬가지로 값이 덮어씌워지는 상황이 발생함

profile
actions speak louder than words

0개의 댓글