Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

C 에서의 문자열

C는 원칙적으로 문자를 문자객체로 다루지 않는다. 애시당초 문자열이란게 존재하지 않으며, 배열로 다룰 뿐이다.
그러므로 우리는 포인터 혹은 배열첨자를 통해서 문자열을 다루어야 하는데, 포인터를 다루어본사람은 알겠지만, 포인터를 통해서 문자열을 다루는 작업은 매우 짜증나는 작업이며, 또한 많은 시간이 투자되는 작업이다.

C에는 이러한 작업을 대신해줄 많은 함수들이 제공되는데, 대부분 "string.h" 헤더파일에 선언되어 있다.

함수설명에 들어가기 전에

strcpy, strcat 같은 함수를 쓰지 않는게 좋다. strncpy, strncat 와 같이 이름에 "n"을 가지고 있는 함수들을 선택하는게 좋다.
이유는 strcpy, strcat 등등의 함수는 얼마만큼의 문자열이 사용될지 그 크기를 지정할수 없으므로, 버퍼오버플로 오류를 일으킬수 있기 때문이다.
이러한 것은 때때로 프로그램버그가 될수 있으며, 이러한 버그를 이용한 크래킹이 가능할수 있기 때문이다.
"n" 이 붙은 함수를 사용하면, 사용되어질 문자열의 크기를 지정할수 있음으로, 필요이상으로 문자열이 사용되는것을 방지할수 있다.
다음 예제를 보라

예제 : strcpy.c
#include <string.h> 
#include <stdlib.h> 

int main()
{
	char *string;

	string = (char *)malloc(15);

	strcpy(string, "hello world");
	strcpy(string, "hello world hello world");
	return 0;
}
string 배열의 크기는 15인데, 2번째보면 그 이상의 문자열이 복사되었다.
위의 명령을 컴파일 해보자.. 안타깝게도, 아무런 에러나 경고 메시지가 떨어지지 않고 프로그램이 컴파일 됨을 알수 있다. 컴파일시 모든 종류의 경고메시지를 보내라는 -Wall 옵션을 줘도 아무런 경고메시지를 뿌려주지 않는다.
[yundream@localhost test]$ gcc -o strcpy strcpy.c -Wall
[yundream@localhost test]$ 
위의 프로그램을 실행시키면 어떻게 될까 ?
잘실행 될때도 있고 그렇지 않을때도 있다.
운이 좋으면 core dump 내고 프로그램 뻗어버릴것이고, (에러가 발생했다는걸 알고 프로그램 디버깅 작업에 들어갈것이므로) 운이 나쁘면 계속 실행될것이고, 잠재적으로 뻗어버릴 위험 혹은 크래킹 당할 위험을 가지는 프로그램이 될것이다.
게다가 저런류의 오류는 디버깅하기도 까다롭다. 그러므로 무조건 "n" 이 붙은 함수를 사용하도록 해야 한다.

문자열 복사 함수

문자열 복사함수는 아마도 가장 빈번히 사용하는 문자열 조작 함수가 될것이다. 다음과 같은 3가지의 함수들이 있다.
#include <string.h>

void *memcpy(void *dest, const void *src, size_t n);
char *strncpy(char *dest, const char *src, size_t n);
char *strcpy(char *dest, const char *src);
void *dest 는 복사되는 목적지의 배열의 포인터이다.
char *dest 는 복사되는 목적지의 문자열의 포인터이다.
const void *src 는 void *dest 에 복사할 배열의 포인터이다.
const char *src 는 char *dest 에 복사할 문자열의 포인터이다.

위의 모든 함수는 dest 의 포인터를 넘겨준다.

memcpy 는 기본적으로 메모리를 복사하는 함수이므로, 형에 관계없이 복사가 가능하다.
반면 strcpystrncpy은 문자열을 복사하는 함수이므로, 단지 문자열에 대해서만 복사가 가능할것이다.
strcpy 는 char *dest 에 얼마만큼 복사될지 크기를 제한할수 없다. 그러므로 strcpy 대신에 strncpy을 사용하도록 한다.

문자열 연결함수

문자열의 뒤에 문자열을 붙이고자 할때 사용한다.
#include <string.h>

char* strcat(char *dest, const char *src);
char* strncat(char *dest, const char *src, size_t n);
char *dest 는 덧붙여질 문자열을 받을 문자열의 포인터이다.
char *src 는 char *dest 에 덧붙일 문자열의 포인터이다.
size_t n 은 복사할 문자열의 크기이다.

strcat 과 strncat 를 사용하면 char *dest 의 마지막 문자인 '\0'이 제거되고, 그 뒤에 char *src 가 붙게 된다.
strcat 는 사용하지말라. 대신 strncat 를 사용하라.

문자열 비교함수

문자열을 비교하기 위해서 사용하는 함수들이다.
비교후 넘겨주는 값에 대해서 혼동할수 있으니 주의 해야 한다.
#include <string.h>

int memcmp(const void *s1, const void *s2, size_t n);
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
const char *s1 는 첫번째 문자열 포인터이다. const void *s1 은 첫번째 메모리 배열의 포인터이다. const char *s2 는 두번째 문자열 포인터이다. const void *s2 는 두번재 메모리 배열의 포인터이다. size_t 는 문자열의 크기이다.

memcpm은 s1과 s2 의 처음 n바이트의 메모리를 비교한다. 만약 s1 이 s2 보다 작으면 0 보다 작은 정수, s1 과 s2 가 같다면 0, s1 이 s2 보다 크다면 0보다 큰정수를 반환한다.

strcmp은 s1 과 s2 의 문자열전체를(널을 만날때까지) 비교한다. s1이 s2 보다 작으면 0 보다 작은정수, 같다면 0, 더 크다면 0보다 큰 정수를 반환한다.

strncmp는 strcmp 와 비슷하지만 n 바이트만큼만을 검사한다. s1이 s2 보다 작으면 0보다 작은정수, 같으면 0, 더크면 0보다 큰 정수를 반환한다.

문자열 찾기

#include <string.h>
void *memchr(const void *s, int c, size_t n);
char *strchr(const char *s, int c);
size_t *strcspn(chst char *s, const char *reject);
size_t *strspn(const char *s, const char *accept); 
char *strpbrk(const char *s, const char *accept); 
char *strchr(const char *s, int c); 
char *strrchr(const char *s, int c); 
char *strstr(const char *s, const char *substring); 
char *strtok(char *s, const char *delim);
memchr s 가 가리키는 메모리 영역에서 문자 c 가 n 바이트영역에 존재하는지 검사한다. n 바이트 영역에서 문자 c 를 발견하면, 발견된 곳의 포인트를 넘겨준다.

strspn 문자열 accept 에 있는 문자들로 이루어져 있는 s 의 초기 문자열의 길이를 계산한다. 길이를 계산한다.

strcspn reject 에 없는 문자들로 이루어져 있는 s의 초기 문자열의 길이를 계산한다.

strpbrk 문자열 s에서 문자열 accept 내의 문자들중 하나가 처음 발견되는 곳을 찾아서 발견된 s문자열의 포인터를 돌려준다.

strchr 문자열 s 에서 문자 c 가 처음발견된곳의 포인터를 반환한다.

strrchr 문자열 s 에서 문자 c 가 마지막 발견된 곳의 포인터를 반환 한다.

strstr 문자열 s 에서 문자열 substring 이 처음발견된 곳의 포인터를 돌려준다. 발견되지 않으면 NULL 을 돌려준다.

strtok man 페이지를 보면 사용해서는 안된다고 경고하고 있다. strtok 가 하는 일은 delim 을 토근으로 해서 문자열을 파싱하는 것이다. 연속 적으로 호출하기 위해서는 처음인자를 NULL 로 설정해야한다. 호출할때 마다 다음 토큰이 발생된 포인터를 반환하며, 더이상 발견되지 않으면 NULL을 반환한다.

문자열 찾기 함수에 대해서 설명을 써놓기는 햇지만, 저게 무슨말인지 알송달송 할것으로 생각된다. 다음 예제를 통해서 확실히 이해할수 있을것이다.
예제 string.c
#include <string.h> 

int main()
{
	size_t n;
	char *tr;

	// 토큰으로 분리할 문자  
	char string[] = "hello\tyundream\thohoho,ok";

	// 토큰 \t 와 , 를 설정하였다. 
	// strtok 로 구분시 \t와 , 로 구분할것이다. 
	char seps[] = "\t,";

	// llo 를 되돌려줄것이다. 
	tr = memchr("hello", 'l', 10);
	printf("%s\n", tr);

	// lohz 에서 loh 는 hello 에 있는 초기 문자열이므로
	// 3을 돌려주게 될것이다. 
	n = strspn("lohz", "hello");
	printf("%d\n", n);

	// kklkd 에서 kk 까지가 hello 에 없는 초기 문자열이름
	// 이므로 2를 돌려주게 될것이다. 
	n = strcspn("kklkd", "hello");
	printf("%d\n", n);

	// kkndel 에서 'e' 가 "hello" 의 문자들중 가장먼저 
	// 일치가 되므로 'e' 가발견된 포인트를 되돌려주므로
	// el 을 넘겨줄것이다. 
	tr = strpbrk("kkndel", "hello");
	printf("%s\n", tr);

	// llo 를 돌려준다.
	tr = strchr("hello", 'l');
	printf("%s\n", tr);

	// 뒤에서 부터 일치되는 문자를 찾게됨으로 
	// lo 를 돌려주게 된다. 
	tr = strrchr("hello", 'l');
	printf("%s\n", tr);

	// llo 를 되돌려준다.
	tr = strstr("hello", "ll");
	printf("%s\n", tr);

	// 토큰 '\t'와 ','로 구분하므로 
	// "yundream" "hohoho" "ok" 3개의 
	// 문자열을 되돌려줄것이다. 
	tr = strtok(string, seps);
	while (tr != NULL)
	{
		printf("%s\n", tr);
		tr = strtok(NULL, seps);
	}

}
위의 프로그램을 컴파일후 실행하면 아래와 같은 결과를 보여준다.
[yundream@localhost yundream]$ ./string
llo
3
2
el
llo
lo
llo
hello
yundream
hohoho
ok

기타 함수

#include <string.h>

void *memset(void *s, int c, sizt_t n);
char *sterror(int errnum);
size_t *strlen(const char *s);
int strcasecmp(const char *s1, const char *s2);
memset 은 메모리를 n 크기만큼을 c 문자로 채운다. 보통은 메모리 할당된 영역을 초기화하기 위해서 주로 사용한다.

sterror 많은 종류의 함수가 에러가 발생했을때, errno 를 돌려주는데, sterror 에 이 errno 번호를 주면, 해당 에러에 대한 내용을 문자열로 되돌려준다.

strlen 자주사용하는 함수일것이다. 문자열의 길이를 돌려주는데, '\0' 을 만나기 전까지의 문자열을 돌려준다.

strcasecmp 대소문자를 구분하지 않고 s1과 s2 문자열을 비교한다. s1 이 s2 보다 작으면 0보다작은 정수, 같으면 0, s1 이 s2 보다 크면 0보다큰 정수를 돌려준다.

다음은 strerror 의 사용예제이다.
에제 streeror.c
#include <string.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 

int main()
{
	if (open("test.test1", O_RDONLY) < 0)
	{
		printf("%s\n", strerror(errno));
		perror("error : ");
		exit(0);
	}
}
위의 코드는 존재하지 않는 파일을 open 하도록 되어 있다. open 함수는 에러를 발생할것이고 errno 를 돌려주게 될것이다.
이 errno 를 strerror 에 넣어주면, errno 에 매칭되는 에러메시지문자열을 돌려준다.
strerror 은 디버깅용도로 많이 사용되는 함수이다.