티스토리 뷰

728x90

☞ strlen, strnlen

<string.h>

size_t strlen(const char *s);
size_t strnlen(const char *s, size_t maxlen);

C언어에서 스트링(String)은 널(NULL, 0)문자로 끝나는 연속적인 char 타입의 바이트 배열로 정의할 수 있으며, char 배열, 스트링 상수, 동적 할당 메모리등에 저장합니다. 그 시작 위치를 char * 포인터 변수에 저장하거나 배열명으로 참조할 수 있습니다. 널 문자는 숫자 0으로 문자 상수로는 '\0'으로 표현할 수 있습니다.

☞ 예제

char *teststr1 = "test string";
char teststr2[30] = "test string";
char *teststr3 = (char *)malloc(30);

strcpy(teststr3, "test string");
printf("\n%d, %d", strlen(teststr1), sizeof(teststr1));
printf("\n%d, %d", strlen(teststr2), sizeof(teststr2));
printf("\n%d, %d", strlen(teststr3), sizeof(teststr3));
printf("\n%d, %d", strlen("test string"), sizeof("test string"));

위의 코드에서 큰 따옴표로 묶인 "test string"를 스트링 상수라고 하며 메모리에는 널 문자를 포함한 크기가 저장됩니다. C 언어 스트링을 자유롭게 다루기 위해서는 스트링의 시작 위치를 저장하는 char * 포인터와 char 배열명의 차이점, 스트링의 시작점과 내용을 다루는 것과는 차이점을 꼭 이해해야 합니다.

변수의 크기를 확인하기 위해서 sizeof() 연산자를 사용 했는데 teststr2 배열은 배열크기 30을 리턴하지만 teststr1과 teststr3는 스트링 상수가 저장된 메모리와 동적 할당 메모리를 가리키고 있는 포인터로 sizeof() 연산자를 사용하면 할당된 메모리의 크기가 아니라 포인터 자체의 크기인 4를 리턴합니다.


스트링을 저장하고 있는 메모리의 종류와 관계없이 스트링 내용이 동일하므로 스트링 길이를 추출하는 위의 strlen() 함수의 결과는 모두 동일하게 11을 리턴합니다. 


strlen()의 인수는 문자열 포인터를 전달해야 하는데 배열명인 teststr2도 포인터로 참조할 수 있음을 확인할 수 있습니다. 주의할 점은 배열명은 참조시에는(r-value) 배열의 시작 위치를 가리키는 포인터로 사용할 수 있지만 teststr2 = teststr1; 처럼 값을 대입시킬 수는(l-value) 없습니다. 


물론 포인터 변수인 teststr1, teststr3에는 포인터 값을 대입할 수 있지만 이 작업은 스트링의 시작 위치만을 대입할 뿐이지 내용을 복사하지는 않습니다. teststr3의 메모리 할당과 복사 과정을 보면 문자열 포인터 다루기에 대한 이해를 도울 수 있습니다.


str...() 관련 함수를 사용할 경우에는 문자열 끝에 반드시 널문자가 있어야 합니다. str...() 함수들은 배열 크기나 할당한 메모리의 크기를 알 수 없기 때문에 문자열 끝에 널 문자가 없는 경우에는 허가되지 않은 메모리에 접근하여 비정상종료가 일어날 수도 있기 때문입니다. 이런 위험성을 예방하기 위해 사용하는 것이 최대 길이 maxlen를 추가로 지정하는 strnlen()과 같은 함수입니다. strnlen()은 maxlen 이내에서 널문자를 만나면 해당하는 길이를 리턴하고 지정 길이 이내에 널문자가 없으면 maxlen을 리턴합니다. 아래는 위의 예제 코드를 수행한 결과입니다.


11, 4
11, 30
11, 4
11, 12



728x90

'C | C++' 카테고리의 다른 글

스트링 연결과 제한된 복사  (0) 2018.05.24
스트링/메모리의 복사와 이동  (0) 2018.05.24
문자 다루기  (0) 2018.05.24
동적 할당 메모리의 크기 변경과 초기화  (0) 2018.05.24
메모리 할당과 해제  (0) 2018.05.24