삽질의 현장/- C

곱씹어보자 C!_#011_ 삽잡이의 두서없이 막말하는 문자열(2)

shovelman 2015. 6. 24. 23:38

으악 머리가 터질거 같네요...

이런 두근 거림... 머리가 터질거 같은데 두근거림...


언어를 하나 완벽하게 습득한다는 것은 무슨 느낌일까요...

이렇게 포스팅도 하면서 그럴 날이 찾아온다면 좋겠네요...

그러기 위한 과정이라 생각하고!

힘이 남아도는 삽잡이는 달리겠습니다! 쉬지않는 오토 마우스~!


#010 문자열(1) 에서는 

배열과 포인터를 사용하며 주소의 연산을 가지고 놀았습니다...

놀았을까요, 끌려 다녔을까요... 하하...


1
2
3
4
 
int* p = arr;
&arr[0= p;
 
cs

이와 같이 할 수 있다는 설명으로 끝을 냈던 것 같습니다...
아무튼... 
배열은 변할 수 없는 상수주소이지만 포인터는 바뀔 수 있다는 점~

문자의 시작 주소만 알면 모든 찾을 수 있다고 했습니다.
맨 뒤에 '\0'이 있고 항상 일정하게 연속된 메모리를 가지고 있기 떄문이라고 했죠...

대괄호 (" ") 안에 있는 문자들의 집합을 문자열이라고 합니다.
문자열을 보면, 컴파일러는 연속하는 문자열 데이터를 만들어냅니다.
예를 들자면 "ABC" 를
'A''B''C''\0' 이렇게 컴파일러가 변환을 한다는 것이죠...


음... 그러니까 

문자열을 보면 메모리상에 연속적으로 저장을 시키고 맨 마지막에 \0을 자동으로 저장시킨다는 것~


실제 코딩에서는 어떻게 담아내는가 하냐면 말이죠...


1
2
3
4
char* s = "ABC";
 
printf("%s\n", s);
 
cs
요런식으로 담아낼 수 있습니다. 근데 여기서 의문점이 2가지가 듭니다.


첫번째, 왜 포인터변수 s인가...

왜냐하면, 지난 시간에 주구장장 얘기했던 것들에 의해서인데요...

연속되는 데이터들의 집합....

'ABC\0' 연속되는 데이터죠... 

이들은 시작주소만을 알면 그 외에 다른 주소들은 문제 없이 찾을 수 있다고 했었습니다.

그렇다면 그 강좌를 생각해보며,

위의 문장은 문자열의 시작주소를 char형 포인터 변수 s에 담겠다라는 뜻으로 해석이 가능합니다.


사실은, char형 포인터에 문자열을 담을 수 있다라고 하지만 

진짜로는 시작주소를 가리키는 것 뿐이죠...


두번째, 왜 char형으로 받는 것인가...

int형 같은 경우에는 하나 증가하면 4 byte가 증가하기때문에...

연속되게 데이터를 담을 수 없습니다...

그리하여 문자열을 나타내는데는 오직 char 포인터만을 사용합니다!


그리고 그 위의 코드를 보면 말입니다.... 

%s를 사용하여 문자열을 출력하고 있습니다.

네 맞습니다. 문자열에는 '%s'를 사용합니다. 정말 중요합니다. 너무너무 중요합니다.

%s 요놈은 '시작주소부터 알아서 내가 \0 만날때까지 출력해줄께'

이런 행위를 해주는 친구입니다.


여기서 중요한 것은 '%s' 이 친구는 시작 주소부터 출력해준다는 것입니다.

주소... 주소입니다... 주소...



1
2
3
4
5
6
7
char* s = "ABC"+1;    
    
printf("%s\n", s); 
printf("%s\n""ABC"); 
printf("%s\n""ABC"+1); 
 
 
cs

문자열의 시작 주소를 가리킨다고 했습니다.

그렇다면 현재 포인터 변수 s에는 '주소' + '1'의 형태로써 1 byte를 건너 뛰었겠습니다.

따라서 s에는 "BC"가 저장되어 있다는 것이죠.


그렇다면 그 아래 세가지의 출력은 어떻게 될까요? 생각해 보시죠...


첫번째, s에는 현재 위와 같이 B의 주소를 가리키고 있기 때문에 "BC"가 출력이 될 것이고,

두번째, "ABC"의 경우 시작주소인 A를 가리키고 있을 터이니 "ABC"가 출력될 것입니다.

세번째, "ABC"+1은 위에서 설명한대로 "BC"가 출력되겠군요.


참고로 문자를 출력해주는 '%c'는 문자열에 사용해서는 안됩니다.

왜냐하면 문자열은 시작하는 주소를 담고 있는데, 문자를 출력하려 하니 제대로 실행이 될 수가 없습니다.


자... 잘들 보고 계신가요... ㅠㅠ... 허허...


다음으로, 문자열을 다루는 방법에 대해서 알아보고자 합니다.


문자열을 다루는데는 크게 두가지의 방법이 있습니다.

첫번째, 문자열의 시작 주소를 가리키는 포인터를 사용하는 방법 (위에서 사용했죠)


두번쨰, 배열을 사용하는 방법입니다.

배열은 연속되는 데이터를 담습니다. 

포인터는 가리키고, 배열은 담고... 약간의 차이가 있습니다...


아무튼... 아래의 코드를 보시죠...


1
2
3
4
5
6
7
8
9
char arr[5= {'A''B''C''D'};
//char arr[5] = "ABCD"; // 위와 동일한 문장.
 
printf("%s\n", arr); // 배열의 이름은 배열의 시작주소이자 문자열의 시작
printf("%s\n", &arr[0]); 
printf("%s\n", arr+1); // B의 시작주소를 알려준것.
printf("%s\n", &arr[1]);
 
 
cs

위의 코드처럼 배열로 문자열을 저장할 수 있습니다. 
첫번째, 출력문인 arr 즉, 배열의 이름은 배열의 시작주소이자 문자열의 시작으로 "ABCD"가 출력 될 것이고요 두번째, 마찬가지로 출력이 되겠군요 
세번째, B가 시작 주소구요 
마지막으로 네번째, 세번째와 마찬가지로 출력 되겠습니다.

배열과 그럼 문자열은 차이가 없을까요? 아닙니다... 
문자열은 마지막에 '\0' 값이 반드시 들어가야한다는 점.
따라서 똑같이 5칸을 선언해도 문자열 같은 경우 반드시 한칸은 사용을 못하죠... 
왜냐하면 '\0' 때문에 말입니다...

그렇다면 이왕 차이점에 대해서 알아본 겸,
포인터로 문자열을 다룰때와 배열로 문자열을 다룰때의 차이점을 알아보도록 해봅시다.

우선, 
문자열의 경우 변경이 불가능합니다. 오직 읽기만 가능한 것이죠.
하지만, 배열의 경우, 변수들의 집합 
즉, 변경이 가능한 메모리이기에 값을 변경할 수 있습니다.


또한,

포인터로 다루는 문자열의 경우, 포인터이기에 size가 4바이트로 고정되어있습니다.

하지만, 배열로 다루는 문자열의 경우, 문자열의 길이에 다라 size가 변경되죠.



이로써 문자열에 대해 다는 아니지만 

알아볼 것들에 대해서는 많이 알아본 것 같습니다...


삽잡이는 계속 달립니다.

푸하하