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