본문 바로가기
C언어

야메 C언어 강좌: 12. 문자열

by 케찹이 2022. 10. 24.

안녕하세요. 포인터 강좌 이후로 오랜만에 돌아왔습니다. 4학년이 되니까 이래저래 바쁘네요 ㅜㅜ

 

어쨌든 이번 시간에는 문자열에 대해서 알아보도록 하겠습니다.

 

 

 

우리는 이전 강의들을 통해서 배열과 포인터를 배워봤습니다. 이거 둘을 사용해서 저희는 문자열을 사용할 수가 있습니다.

 

문자열과 문자의 차이는 무엇인가요?

앞에서 우리는 문자를 char변수에 저장을 한다 라는 것을 배웠었고 char변수 같은 경우에는 딱 한 문자만 저장을 할 수 있었습니다.

반면 오늘 배울려는 문자열은 여러문자의 연속입니다. 

둘의 차이를 정리하자면 아래와 같습니다.

// 문자의 예시 'a', 'b', 'c'
// 문자열의 예시 "abc", "hello", "string"

// 문자는 ''로 감싸주고 문자열은 ""로 감싸주어야 합니다.

 

그럼 우리는 문자열 같은 경우 어떻게 나타낼 수 있을가요?

우리가 저번 시간에 배웠던 배열을 통해서 문자열을 표현이 가능합니다. 한번 볼까요?

#include <stdio.h>

int main(){
	char str[11] = {'I',' ','a','m',' ','s','t','r','i','n','g'};
	
	for(int i = 0; i < 11; i++){
		printf("%c", str[i]);
	}
	return 0;
}

 

char str[11] 에 문자들을 집어넣었고 이전에 우리가 배웠던 for문을 통해서 모든 str배열안에 있던 문자들을 하나씩 출력을 하면서 "I am string"이라는 문자열을 출력을 해보았습니다. 

 

물론 이렇게도 문자열을 표현할수는 있겠지만 만약에 우리가 1000개 또는 100만개의 문자를 배열에 저장할려고 하려면 도대체 몇개의 ' ' 를 적어야될까요. 당장 11개만 적어도 굉장히 헷갈렸고 이렇게되면 에러가 생길 확률도 있겠죠.

 

그래서 C언어에서는 주로 이렇게 문자열을 표현합니다.

#include <stdio.h>

int main(){
	
	char* str = "I am string";
	printf("%s\n", str);
	 
	return 0;
}

딱봐도 굉장히 코드가 줄었죠! 

문자열을 표현하기 위해서 우리는 char* 이라는 표현을 사용하였습니다. 말로 하자면 char의 포인터로 문자열을 저장한 것이죠. 

 

char의 포인터, char의 포인터,char의 포인터, char의 포인터,char의 포인터, char의 포인터,char의 포인터

 

이 표현을 다시 한번 리마인드 해보시기 바랍니다. 포인터란 뭐였죠? 주소였습니다. 

 

물론 저번 포인터에서는 int형식으로 예시를 보여드렸지만 이번에는 char의 배열 형식으로 바꾼 것입니다. 그래서 위의 코드를 잠깐 변형해서 설명드리자면 아래와 같습니다.

#include <stdio.h>

int main(){
	char str[11] = {'I',' ','a','m',' ','s','t','r','i','n','g'};
	
	char* str_pointer = str;
	printf("%s\n", str_pointer);
	 
	return 0;
}

str_pointer라는 char형 포인터는 str이라는 문자형 배열을 가리키게 됩니다. 밑 그림은 제가 저번 포인터 수업때 사용했던 그림입니다. 

지금도 저 상황과 거의 비슷한 상황인것입니다. 밑에 그림과 같이 이해를 하면 되겠습니다.

자 여기까지는 저번 수업과 굉장히 흡사하고 저번 포인터에 대해서 잘 이해하셨다면 위의 내용도 문제 없이 이해하셨을 겁니다.

 

하지만 죄송합니다. 제가 위에서 거짓말을 한 부분이 있습니다.  ^^

 

바로 위에 있는 그림에 잘못된 것이 있습니다. 사실 저의 강좌에서 제일 추구하는 것은 "야메", 즉 대충, 쉽게 C언어를 가르치는 것인데 윗 그림을 포인터에서 설명한 관계로 밑에 내용을 설명하도록 하겠습니다. 

 

우리는 변수들을 메모리에 저장을 하는 것인데 이전에 배웠던 int 그리고 char 같은 경우에는 메모리에 이런식으로 저장이 됩니다.

여기 메모리를 큰 사각형으로 나타내었습니다. 메모리안에는 char형인 'a'가 저장이 되어있고 int형인 100이 저장이 되어있습니다. char은 1바이트, int은 4바이트를 차지하고 있기 때문에 저렇게 그려져있습니다.

비록 제가 그림은 저렇게 그렸지만 항상 메모리 최상단에서 순서대로 메모리에 채워지는 것은 아닙니다. 그리고 각 변수는 자신만의 주소가 존재하게 되겠죠. 

 

그럼 우리가 위에서 봤던 마지막 코드의 상황을 한번 메모리에 어떻게 저장이 되었는지 살펴보겠습니다.

일단 첫번째 특징은 배열의 값들은 연속되어서 저장이 되어져있습니다. 위 그림에서 str에 저장되어 있는 값들은 서로 연속되게 저장이 되어있는 것을 확인할 수 있습니다.

두번째 특징은 배열의 각 원소 값들은 각각 따로 주소값을 가지고 있는 것입니다. 생각해보면 당연한 것입니다. 하나의 char에는 하나의 주소가 가지고 있으니까 여러 char을 저장하는 배열은 각 원소마다 자신의 고유 주소를 가지게 되는 것이죠.

세번째 특징은 str_pointer의 크기입니다. 포인터 변수의 크기는 char의 포인터인지, int의 포인터인지, long의 포인터인지 상관없이 크기가 4바이트로 고정이 되어있습니다.

그리고 마지막 특징은 str_pointer가 포인팅하고 있는 값입니다. 해당 배열의 포인터는 배열의 첫번째 원소의 주소의 값을 가지게 됩니다. 이렇게 되면 밑과 같은 표현이 가능합니다.

#include <stdio.h>

int main(){
	char str[11] = {'I',' ','a','m',' ','s','t','r','i','n','g'};
	
	char* str_pointer = str;
	for(int i = 0; i < 11; i++){
		printf("%c", *(str_pointer+i));
	}
	return 0;
}

str_pointer는 결국 str의 첫번째 원소인 'I'의 주소값을 가지고 있으니까 *str_pointer는 ' I '가 되겠습니다.그리고 위에서 언급한 마지막 특성 때문에 *(str_pointer+1)을 하게 되면 ' '를 출력하고 +2, +3, +4, ... , +10까지 하면 str의 모든 각 원소에 접근할 수가 있습니다.

각 *(str_pointer + n)을 정리하면 다음과 같습니다:

 

*(str_pointer) = I

*(str_pointer + 1) = ' ' (그냥 space)

*(str_pointer + 2) = a

*(str_pointer + 3) = m

*(str_pointer + 4) = ' '(그냥 space)

*(str_pointer + 5) = s

*(str_pointer + 6) = t

*(str_pointer + 7) = r

*(str_pointer + 8) = i

*(str_pointer + 9) = n

*(str_pointer + 10) = g

 

여기서 +1이라는 것에 대해서 "도대체 이것이 메모리에서 실제 얼만큼의 크기인가"를 궁금해하실 수 있습니다.

제 답변을 두가지로 드리면

첫번째 야메 답변입니다: 배열 포인터의 값+1은 가리키고 있는 배열의 두번째 원소를 뜻하고, +2는 세번째 원소, +3은 네번째 원소, +4은 다섯번째 원소... 여기까지만 아시면 되겠습니다.

 

두번째 답변입니다: 이 크기에 대해서는 int, char, long다 각 크기가 달라서 해당 질문을 하실 수가 있습니다. 예를 들어서 char배열 같은 경우에는 char가 1바이트이기 때문에 첫번재 원소의 주소에다 +1해서 다음 원소를 가리키고 int배열 같은 경우에는 4바이트이기 때문에 첫번째 원소의 주소에다 +4를 해서 다음 원소를 가리키지않아야 되나 라는 생각을 하실 수 있는데 다행히 그렇지 않습니다. 실제 주소는 그렇게 증가를 하겠지만 프로그래머의 코드 편의성을 위해서 가르키는 변수의 종류에 상관없이 단순히 +1를 해서 다음 원소의 값을 가리키게 됩니다. 

 

 

 

많이 어려우셨을까요;; 사실 제 강의에 "아메"라는 타이틀을 처음 걸면서 부터 오늘 이부분을 어떻게  간단하게 설명하지? 라는 생각을 했었습니다. 막상 쓰고 보니까 여전히 어렵네요, 하지만 제가 자신있게 얘기하지만 이 부분을 완벽히 이해하셨다면 뒤에 배우는 내용들은 정말 쉽다고 얘기할 수가 있습니다. 항상 어려우시면 댓글 남겨주시고 이해를 다 하셨다면 한번 번 실제 코드를 작성하여서 익숙해지시고 내 마음대로 이런저런 방식대로 코딩을 해보세요. 그때 의문점들이 나오게 되고 더 편한 방법들을 스스로 찾게 되는 자신을 발견하실 수 있습니다. 긴글 봐주셔서 감사합니다!

댓글