오늘은 strcpy() 함수랑 놀아 봅시다...
strcpy() 함수에 포인터를 잘못 사용하면 프로그램은 다운됩니다.
다음 대화를 통해 strcpy() 함수를 완벽하게 이해하여 봅시다.
딩동~~ strcpy() 님이 입장하셨습니다.
김은철 : 야.. 너 이리와 봐...
strcpy : 네.. 저요? 긁적.. 긁적.. ㅠ.ㅠ
김은철 : 어... 너. 너가 애덜 괴롭힌다며?
strcpy : 그런 적 없는데요...
김은철 : 그런데.. 애덜이 너만 보면 왜 떨어?
strcpy : 몰라~요. 갸네들 혹시 떨녀 아녜요?
김은철 : 웃기셔... 애덜이 너를 고발했거든..
strcpy : 머라구요?
김은철 : 잘 가다가.. 너만 만나면.. 프로그램이 다운된다잖아.
strcpy : 저도 미치겠어요.. 그런 애들 때문에 저도 매일 운영 체제한테 혼나요. 아무 번지나 마구 접근한다고. ㅠ.ㅠ
김은철 : 어떤 상황이길래 그러는데?
strcpy : 보실래요? 애덜이 어떻게 저를 괴롭히나... 아래를 보세요. 아래처럼 하면 제가 혼나겠어요? 안혼나겠어요?
char* p = "사랑스러워";
char buf[10];
strcpy( buf, p );
김은철 : 무슨 문제라도?
strcpy : 사랑스러워가 10자리잖아요. 그리고 문자열이니까.. 끝에 널 문자가 추가되어야 하잖아요. 그런데 꼭 저런 애들이 있어요... buf[10]이잖아요. 그럼 제가 널 문자를 복사하다 보면, 다른 애들이 있는 곳까지 침범하게 되요... 이러면 다른 애들이 불평을 하죠.. 왜 자꾸 내 영역까지 오냐구... 내가 거기에 가고 싶냐구요. 애덜이 저렇게 복사하라고 하니까 어쩔 수 없이 복사하다 보면, 다른 애들이 있는 영역까지 침범해서 1바이트를 더 쓰게 되죠.
김은철 : 너가 알아서 10바이트만 복사하면 되잖아.
strcpy : 저는 그런 것 못해요.. 그냥 시키면 시키는 데로 할 뿐이죠.
김은철 : 단순하네.. 너가 알아서 하면.. 프로그램이 다운되는 그런 일은 발생하지 않을 텐데.
strcpy : 그럼 알아서 할 수 있게 저의 기능을 바꿔 주세요.
김은철 : 켁~ㅠ.ㅠ 그럼, 저런 상황은 해결책이 전혀 없어?
strcpy : 있지요. buf[11]이라고 해주면 되지요.
김은철 : 그러면 해결돼?
strcpy : 네.. 그런데.. 만약 buf[11]이라고 한 후, 아래처럼 또 버퍼보다 많은 문자열을 복사하면 마찬가지로 다른 영역을 침범하게 되겠죠. 그러니까 복사할 버퍼보다 많은 버퍼를 선언해 주는 방법 외엔 해결 방법이 없어요.
strcpy( buf, "1234567890123" );
김은철 : 그럼 그건 그렇게 해결하면 되고, 다른 불만도 있던데 그건 어떻게 해결할꺼야?
strcpy : 뭔데요?
김은철 : 문자열을 복사하라고 했더니 프로그램이 다운되더래.
strcpy : 어떻게 했는데요?
김은철 : 다음 코드를 봐봐봐봐봐... 너가 저걸 안 해 준다며?
char* p;
strcpy( p, "밥 같이 먹을래 말래" );
strcpy : 켁.. 안 해 주는 게 아니죠. 포인터가 가리키는 곳이 없잖아요. 포인터 p는 쓰레기 번지를 갖고 있네요. 잠시 기다려 봐요.. 제가 복사를 시도해 볼게요.
(운영체제한테)p는 쓰레기 번지인 74847483번지를 가리키고 있습니다. 이 곳에 "밥 같이 먹을래 말래"를 복사해 달라는 친구가 있는데요. 가능한가요?
운영체제 : 그 번지 그 놈꺼니?
strcpy : 몰라요.. 그 번지에다 복사해 달라네요.
운영 체제 : 잠시만... (메모리를 관리하는 팀에 조회 중...) 74847483번지를 접근하고 싶다는데 가능해? (어.. 안돼? 왜? 다른 애가 사용 중이라고? 알떠) 안된데.
strcpy : 안돼요?
운영 체제 : 어.. 안돼. 허락되지 않은 번지에 침범한 것은 잘못된 거야.. 그 프로그램 다운시켜야겠다. 다른 프로그램의 안전을 위해서. 그렇게 알어.
strcpy : 나 죽어... 살려~~~~~~~ 켁 OTL
김은철 : 야! 어디갔냐?
strcpy : 다운됐어요.. 그러니까.. 그런애들 때문에.. 저만 매일 혼나요. 복사할 수 있는 번지를 줘야 복사를 해 주죠.. 꼭 이상한 번지를 줘서.. 복사를 하려 하면 운영 체제가 잘못된 번지에 접근한다고 즉시 프로그램을 다운시켜 버리잖아요.
김은철 : 그럼 복사할 수 있는 번지를 주면 복사는 잘 해 주남?
strcpy : 네.. 당연하죠.
김은철 : 이건 그럼 왜 안 되는데? "왜왜왜"를 복사해 주란 말이지.
strcpy( "야야야", "왜왜왜" );
strcpy : 켁.. 그 것도 갈 때마다 운영 체제한테 혼나는 거에요.
김은철 : 왜?
strcpy : "야야야"는 복사할 수 있는 버퍼가 아니라 문자열 상수잖아요. 문자열 상수 영역에다가 복사해 달라고 하면, 운영 체제한테 혼나요. 제가 부탁하면.. 바로 프로그램 다운돼요.
김은철 : 정말이야? 사실이야?
strcpy : 네. 운영 체제는 메모리라고 해서 다 복사해 주는 것이 아니에요. 메모리가 상수 영역으로 사용되고 있을 때는 값을 읽는 것은 허락해 주지만, 그 곳에 뭔가를 쓰면 안돼요.. 만약에 미술관에 가서 그림을 보다가 그 곳에 다른 그림을 그리면 어떻게 되겠어요?
김은철 : 경찰서로 가겠네.
strcpy : 그렇죠? 그러니까 쓰기가 허락되지 않은 곳에 뭔가를 쓰면 안돼요.
김은철 : 좋아.. 그럼 이건 왜 안 되는데? buf1이 복사할 수 있는 버퍼잖아.
char buf1[100];
char buf2[200];
strcpy( buf1, buf2 );
strcpy : 켁.. 미쳐.. 미쳐.. buf1이 복사할 수 있는 버퍼는 맞는데요... buf2에 널 문자가 없네요. 저는 buf2를 복사하다가 널 문자를 만나면 복사를 그만하거든요. 그런데 buf2가 아무 초기화도 되지 않았으니까 쓰레기값만 꽉 차 있겠네요. 저는 문자열을 어디까지 복사할 지를 널 문자를 판단해서 알아내요. 그런데 문자열의 끝에 널 문자가 없으면, 어디까지 복사를 해야 할 지 알 수 없어요.. 저럴 경우 프로그램은 다운되지 않을 수는 있지만, 다른 영역을 침범해서 프로그램이 오동작하는 경우가 발생되죠.
김은철 : 크~~~ 뭐가 그리 복잡하다냐? 대충.. 인생 머 있다구...
strcpy : 그렇죠.. 저런 것을 사용하는 애들이 포인터의 개념과 문자열의 개념이 부족하기 때문에 항상 문제아들로 분류되어 있어요. 위에 그런 애들 말고 다른 애들도 있어요. 다음을 봐봐봐요. 자기 딴에는 머리를 쓴다고 해 놨는데... 결국 p가 가리키는 곳이 문자열 상수 영역이기 때문에 또 프로그램 다운이에요.
char* p = "야야야";
strcpy( p, "왜왜왜" );
김은철 : 잠시만.. "야야야"가 문자열 상수야?
strcpy : 네.. 문자열 상수죠.
김은철 : 문자열 상수는 변수랑 다른가?
strcpy : 많이 다르죠... 문자열 상수는 컴파일이 되는 즉시 그들만의 고유한 메모리 영역에 생성되고, 문자열을 읽을 수만 있고, 그 곳을 다른 값으로 변경할 수 없도록 운영 체제가 관리해요. 그래서 문자열을 변경하려고 시도하면 바로 다운되요.
김은철 : 그럼.. 컴파일러가 미리 미리 컴파일 에러를 내면 편하겠네.
strcpy : 맞아요. 그러면 되는데 컴파일러는 단순해서 char*형인가만 조사하고 그 곳이 상수 영역인지 변수 영역인지는 조사해 주지 않아요. 제가 컴파일러를 만든다면 그런 것도 조사해 주겠어요. 그래야 프로그래머가 고생을 안하죠.
김은철 : 그러네.. 컴파일러가 바보네...
strcpy : 다음은 어떻게 될 것 같아요.. 한 번 맞춰보세요.
char buf[100];
char* p = buf;
strcpy( p, "야야야... 왱" );
김은철 : p가 가리키는 곳이 buf이고, 거기에 복사를 하니까.. 잘 되겠네.
strcpy : 맞췄어요. 그럼 이거는요?
int i;
strcpy( &i, "야" );
김은철 : 그건 머데?
strcpy : ㅋㅋㅋ 모르겠어요? i가 4바이트이니까 그 곳에 "야"를 복사하라는 것이죠.
김은철 : 저것이 가능해?
strcpy : 그럼요.. 가능하죠.. 일반적으로 사용되지는 않지만 i도 메모리를 갖는 4바이트 버퍼니까 가능해요.
김은철 : 허허...
strcpy : 그럼 이거는요?
char ch;
strcpy( &ch, "야" );
김은철 : 그건 이상하네... ch가 1바이트이고, "야"는 널 문자까지 3바이트이니까, 다른 변수들의 영역까지 침범 당하겠네.
strcpy : ㅋㅋㅋ 그렇죠? 그런데 아니에요. char형 변수는 그 크기가 1바이트인데, 실제로는 4바이트 공간을 할당해서 1바이트만 사용하는 거에요. 그러니까 저렇게 하면 잘 복사돼요. 다음과 같이 출력을 해 보면, "야'가 잘 출력되는 것을 볼 수 있어요.
puts( ch );
김은철 : 음.. OTL이군.. 그건.. 그런 건 모르는 편이 좋겠네.
strcpy : 그렇기는 해요.. 하지만 변수와 메모리 크기 등의 관계를 잘 알아야 나중에 진정한 고수가 될 수 있어요.
김은철 : 그렇구나.. 초보인지 아닌지는 strcpy() 함수를 얼마나 이해하고 쓰는지를 보면 되겠네.
strcpy : 맞아요.. 저를 잘 아는 애들은 초보는 아니죠...
김은철 : 밤이 늦었네... 담에 또 보자고.
strcpy : 네.. good night 요~
|