Developer

18.(C언어) 문자열 본문

Programming Language/C

18.(C언어) 문자열

DPhater 2020. 8. 1. 21:39

문자열은 말 그대로 문자의 나열이다.

지금까지 char형 변수에 문자를 하나씩 저장하여 사용하였다.

char ch='a'; 문자 a를 ch에 할당 문자열은 이러한 문자들의 나열이다. 처음 C를 시작할때 printf함수로 출력한

"Hello World!"또한 문자열이다. 문자는 작은따옴표로 감싸주고 문자열은 큰 따옴표로 감싸주는것을 기억하자!

C++에서는 string이라는 문자열을 저장하는 자료형이 따로 존재하지만 아쉽게도 C에서는 문자열을 저장하는 자료형이 따로 존재하지 않는다. C에서는 문자열을 처리하기 위해 포인터와 배열을 사용한다. 물론 char 자료형을 사용하여야 한다.

문자열과 포인터

#include<stdio.h>

int main(){
	char *ch="Study";
	printf("%s\n",ch);
	return 0;
}

코드1 실행 결과

포인터는 메모리 주소를 저장한다는것을 포인터를 공부하며 알게되었다. 따라서 코드1에서 ch는 "Study\0"라는 문자열의 주소를 가리키고 있는것이다.

상수에서 배웠듯이 "Study"는 문자열 리터럴이다. 이 문자열 리터럴은 메모리 공간 어딘가에 읽기 전용으로 저장되고, 이러한 문자열 리터럴의 주소를 ch가 가리키고 있는것이다. 물론 읽기 전용이므로 수정하거나 다른 문자열로 덮어쓸 수 없다.

 문자열을 출력할 때는 %s라는 문자열 서식 지정자를 사용한다. 근데 위의 그림에서 보면 우리가 작성한 Study만 메모리에 저장된것이 아니라 마지막에 NULL이 저장된 것을 볼 수 있다. 직접 작성한 우리는 y가 문자열의 마지막이라는 것을 쉽게 알 수 있지만, 포인터는 어디가 문자열의 끝인지 알 수 없다.

 그렇기 때문에 문자열의 마지막에 NULL문자를 넣어서 문자열의 끝을 나타내는 것이다. NULL문자는 \0이다. 코드1의 printf함수는 ch가 가리키고 있는곳의 문자열을 출력하다가 NULL을 만나면 멈추게 된다.

포인터는 배열처럼 사용이 가능하다고 배웠다. 그렇기 때문에 우리는 대괄호와 인덱스를 사용해 원하는 문자 하나만 사용할 수 있다.

#include<stdio.h>

int main(){
	char *ch="Study";
	printf("%c\n",ch[2]);
	printf("%c\n",*(ch+3));
	printf("%c\n",ch[5]);
	return 0;
}

코드2 실행 결과

문자 하나만을 출력하므로 서식 지정자는 %c를 사용해야한다. 배열의 index는 0부터 시작하므로 ch[2]는 3번째 문자인 'u'를 가지고있다. *(ch+3)은 포인터 연산과 역참조를 이용한 방법으로 포인터를 배울때 이미 공부하였다. *(ch+3)은 ch[3]과 같으며 4번째 문자를 가지고있다. ch[5]의 경우 문자열의 마지막을 나타내는 NULL문자인데 NULL문자는 출력하면 아무것도 보이지 않는다.  주의할 점은 ch에 저장된 값은 읽기전용 이므로 ch[3]='A'와 같이 값을 변경할 수 없다.

문자열과 배열

#include<stdio.h>

int main(){
	char s[10]="Study";
    //char s1[10];
    //s1="Study1";
	printf("%s\n",s);
	return 0;
}

코드3 실행 결과

배열을 이용해 문자열을 저장할 경우 코드3 처럼 초기화를 통해 저장해야한다.

주석 처리된 부분처럼 이미 선언된 배열에는 문자열을 할당할 수 없다.

이미 선언된 배열에 문자열을 할당하려면 각 요소별로 문자를 하나씩 넣어야한다.

코드3의 char형 배열을 보면 크기가 10으로 선언된것을 알 수 있다. 하지만 Study는 5글자이다. 그럼 남은 공간은 어떻게 될까?  우선 문자열의 끝을 알리는 NULL문자가 6번째 자리에 들어가게된다.

뒤에 남는 요소들은 무엇이 들어가도 상관이 없지만 보통 남은 공간에도 NULL이 들어간다.

코드3에서는 배열의 크기가 문자열의 크기보다 충분히 크기때문에 문제가 없지만 배열에 문자열을 저장할때는 배열의 크기에 항상 주의 하여야 한다. 문자열의 길이만 신경쓰는것이 아닌 문자열의 끝을 알려주는 NULL문자가 들어갈 공간까지 생각을 해줘야한다. 쉽게 말해서 문자열의 크기+1 이상의 크기의 배열을 만들어야 한다.

배열에 저장된 문자열은 포인터로 저장한 문자열과 다르게 각 요소의 수정이 가능하다.

#include<stdio.h>

int main(){
	char s[10]="Study";
	s[2]='t';
	printf("%s\n",s);
	return 0;
}

코드4 실행 결과

s[2]에 t라는 문자를 저장하고 출력을 했다. s[2]는 문자열의 3번째 요소이므로 (배열의 index가 0부터 시작하는걸 잊지말자) Study의 u가 t로 바뀌어 출력된는 것을 확인할 수 있다.

#include<stdio.h>

int main(){
	char s[10];
	char s1[10];

	scanf("%s",s);
	scanf("%s",s1);

	printf("%s\n",s);
	printf("%s\n",s1);

	return 0;
}

코드5 실행 결과

s와 s1두개의 배열을 선언한 뒤 scanf로 입력한 문자열을 배열에 저장하였다. 여기서 주의할점은 scanf함수 사용시 &(주소연산자)를 사용하지 않았다는 것이다.  scanf함수의 두 번째 인자에는 주소를 입력해 줘야한다.

배열도 포인터처럼 첫 요소의 주소를 담고 있으므로 &는 사용하지 않는다.

s의 경우 입력한 문자열 Study가 정상적으로 출력된다. 하지만 "i love it"이라는 문자열을 s1에 입력했지만 출력했을때 i밖에 출력이 되지않았다. 이는 scanf에서 %s로 문자열을 저장할 때 배열에는 공백 직전까지만 저장되기 때문이다.

#include<stdio.h>

int main(){
	char s[10];
	scanf("%[^\n]s",s);
	printf("%s\n",s);
	return 0;
}

코드6 실행 결과

공백을 포함해서 문자열을 저장하고 싶다면 코드6과 같이 서식 지정자를 %[^\n]s 와 같이 사용하면 된다.

visual studio 의 경우 char *에 리터럴 문자열을 넣으면 error가 발생한다. char앞에 const를 붙히면 문제없이 실행이 가능

'Programming Language > C' 카테고리의 다른 글

20.(C언어) 구조체(1)  (0) 2020.08.01
19.(C언어) 문자열 함수  (0) 2020.08.01
17(C언어) 동적할당  (0) 2020.08.01
16.(C언어) 배열  (0) 2020.08.01
15.(C언어) 포인터  (0) 2020.08.01
Comments