책정리/혼자 연구하는 C,C++ 1

12장 문자열 함수

GONII 2015. 2. 19. 17:47

12.1 문자열 함수

12.1.1 문자열 복사

C언어에서 문자열은 널 종료 문자가 끝에 있는 문자 배열로 표현하며 기본 타입에 포함되지 않는다.

   

str1 = "korea" ; // 문자열 상수를 대입할 수 없음

str1 = str2 ; // 배열끼리도 대입할 수 없음

str3 = str1 + str2 ; // +연산자로 문자열을 연결할 수 없음

if ( str1 == str2 ) // == 연산자로 문자열끼리 비교할 수 없음

   

문자열이 기본 타입이 아니다 보니 정수나 실수처럼 연산자를 사용할 수는 없지만 문자열 함수를 사용하면 내용을 바꾸거나 비교, 연결하는 것은 물론이고 검색, 변환 등 연산자보다 훨씬 더 다양한 작업을 효율적으로 처리 할 수 있다.

   

  • 문자 배열에 문자열을 복사하는 함수

    char *strcpy( char*dest, const char *src ) ;

    dest는 복사될 목적지이고, src는 복사될 원본 ( dest = src )

    NULL 문자도 같이 dest에 복사됨

       

    dest의 공간은 NULL 문자를 포함한 src의 데이터를 모두 담을 수 있는 크기로 되어 있어야 한다.

  • 지정한 길이만큼 복사하는 함수

    char* strncpy( char*dest, const char* src, size_t count ) ;

  • 예제 strncpy

#include <stdio.h>

#include <string.h>

   

void main ( void )

{

char str1[10] = "abcdefghi" ;

char str2[10] = "123456789" ;

   

strncpy( str2, str1, 3 ) ;

puts(str2) ;

}

strncpy 함수는 문자열의 일부분을 다른 부분 문자열로 바꾸고 싶을 때 사용한다.

문자열 시작 부분이 아니라 중간의 일부를 바꾸고 싶다면 복사할 시작 위치를 옮기면 된다.

strncpy( str2+2, str1+2, 3 ) ;

  • 예제 strncpy2

#include <stdio.h>

#include <string.h>

   

void main ( void )

{

char str1[10] = "abcefghi" ;

char str2[10] = "123456789" ;

   

strncpy( str2+2, str1, 3 ) ;

puts(str2) ;

}

   

12.1.2 문자열 연결

문자열 연결이란 한 문자열 끝에 다른 문자열을 덧붙이는 것이다.

   

char *strcat(char *dest, const char* src ) ;

char *strncat( char *dest, const char *src, size_t count ) ;

   

char dest[20] = "이순신" ;

char src[] = " 장군" ;

strcat( dest, src ) ;

dest의 끝에 있던 널 문자 자리에 src 문자열이 추가된다.

   

  • 예제 strcat

#include <stdio.h>

#include <string.h>

   

void main ( void )

{

char si[] = "서울" ;

char ku[] = "동대문" ;

char dong[] = "회기" ;

char juso[64] ;

   

strcpy( juso, si ) ;

strcat( juso, "시 " ) ;

strcat( juso, ku ) ;

strcat( juso, "구 " ) ;

strcat( juso, dong ) ;

strcat( juso, "동" ) ;

   

puts( juso ) ;

}

12.1.3 문자열 비교

문자열 비교 함수는 두 문자열이 같은지 다른지, 다르면 어떤 문자열이 더 큰지 비교한다.

   

int strcmp( const char *s1, const char *s2 ) ;

int strncmp( const char *s1, const char *s2, size_t count ) ;

   

strcmp 함수는 string compare의 약자이며 가장 기본이 되는 비교 함수이다. 이 함수들은 인수로 주어진 두 문자열을 비교한 후 그 결과를 다음과 같이 정수값 하나로 리턴한다.

s1 과 s2가 같으면 0

s1 > s2 이면 양수

s1 < s2 이면 음수

두 문자열의 대응되는 문자들을 차례대로 비교해 나가다가 최초로 다른 문자가 발견되면 두 문자의 코드값을 그대로 뺄셈해서 리턴해 버린다. 그래서 비교 결과도 부호로 판별해야 한다.

"ABC" 와 "ABC"는 같다. 비교 결과는 0 이다.

"ABC" 는 "ABD"보다 작다. 비교 결과는 음수이다.

"ABC" 는 "ABB"보다 크다. 비교 결과는 양수이다.

  • 예제 strcmp

#include <stdio.h>

#include <string.h>

   

void main ( void )

{

char capital[16] ;

   

printf("우리나라의 수도는 어디입니까?") ;

scanf("%s", capital) ;

   

if ( strcmp(capital, "서울") == 0 )

{

printf("정답\n") ;

}

else

{

printf("오답\n") ;

}

}

strncmp 함수는 지정한 개수만큼만 문자열을 비교한다.

   

  • 대소문자 구분없이 문자열을 비교하는 함수

    int stricmp( const char *string1, const char *string2 ) ;

    int strnicmp( const char *string1, const char *string2, size_t count ) ;

       

    함수명 중간에 i가 삽입되어 있는데 i는 Ignore, 즉 대소문자 구성을 무시하고 비교한다는 뜻이다.

    MSDN에서 이 함수들을 찾아보면 함수명 앞에 _가 붙어있는 함수로도 정의되어 있어 둘 다 사용 가능하다.

12.1.4 문자열 검색

문자열 검색 함수는 문자열 중 특정 문자나 부분 문자열의 위치를 찾는다

char *strchr( const char *string, int c ) ;

char *strrchr( const char *string, int c ) ;

char *strstr( const char *string, const char *strSearch ) ;

char *strpbrk( const char *string, const char *strCharSet ) ;

char *strtok( char *strToken, const char *strDelimit ) ;

   

strchr 함수는 문자열 중 c라는 문자가 있는지 찾아 그 포인터를 리턴한다.

만약 지정된 문자가 발견되지 않으면 NULL을 리턴한다.

   

strrchr 함수는 문자열의 뒤에서부터 문자를 검색하는데 함수명에 포함된 r은 rear, 즉 뒤쪽이라는 뜻이다.

   

  • 예제 strchr

#include <stdio.h>

#include <string.h>

   

void main ( void )

{

char str[256] ;

char *ptr ;

int count = 0 ;

   

printf("아무 문자나 입력하세요(공백없이 최대 255문자) ") ;

scanf( "%s", str ) ;

for ( ptr=str ;; )

{

ptr = strchr ( ptr, 'a' ) ;

if ( ptr == NULL )

{

break ;

}

count++ ;

ptr++ ;

}

   

printf("입력한 문자열에는 a가 %d개 있습니다.\n", count ) ;

}

   

strstr 함수는 문자열에서 부분 문자열을 찾는다.

   

strpbrk 함수는 여러 번 검색해야 하는 작업을 간단하게 끝낼 수 있다.

이 함수는 첫 번째 인수로 주어진 문자열에서 두 번째 인수로 주어진 문자열에 속해 있는 문자 중 가장 먼저 발견된 문자를 찾아 그 번지를 리턴한다.

char str[] = "Four score and sven years ago" ;

char *ptr = strpbrk( str, "def" ) ;

str에 긴 문자열이 들어 있는데 이 문자열 중에서 d나 e나 f 중 가장 먼저 발견되는 문자를 찾아 ptr에 대입한다. 문자열에서 여러 개의 문자 중 하나를 찾고자 할 때는 이 함수를 사용하면 된다.

   

strtok 함수는 문자열을 토큰으로 잘라낸다. 예를 들어 "서울/대전/대구/부산" 문자열을 "/" 구분자로 자르면 서울, 대전, 대구, 부산 4개의 문자열로 분할 할 수 있다.

첫 번재 인수로 잘라낼 문자열을 주며 두 번째 인수로 구분자를 구성하는 문자열을 준다. 구분자는 한 문자열에 여러 개를 지정할 수 있는데 /와 :그리고, 가 토큰 구분자라면"/:,"를 준다.

  • 예제 strtok

#include <stdio.h>

#include <string.h>

   

void main ( void )

{

char str[] = "I am a boy, you are a girl" ;

char *p ;

   

p = strtok( str, " ," ) ;

   

while( p!= NULL )

{

puts(p) ;

p = strtok( NULL, " ," ) ;

}

}

   

   

strtok 함수는 주의해서 사용해야 한다. 우선 토큰이 발견될 때마다 널 문자열로 만들기 위해 검색 대상 문자열을 변경한다는 점이 다른 검색 함수와 다르다. 그래서 검색 대상이 문자열이 변경되지 말아야 할 경우는 반드시 사본을 복사한 후 사본에서 토큰을 추출해야 한다.

또한 이 함수는 검색 중간 결과, 즉 어디까지 검색했는지를 스스로의 정적변수에 저장한다는 점이 특이한데 정적변수를 사용하기 때문에 검색 중에 새로운 검색을 할 경우 이전 검색에 대한 정보는 잃어버린다.

   

12.1.5 문자열 변환

char *strset( char *string, int c ) ;

char *strnset( char *string, int c, size_t count ) ;

char *strlwr( char *string ) ;

char *strupr( char *string ) ;

char *strrev( char *string ) ;

   

strset 함수는 문자열을 c문자로 가득 채운다.

strnset 함수는 개수를 지정하여 c로 채운다.

strlwr 함수는 모든 문자를 소문자로 바꾼다.

strupr 함수는 모든 문자를 대문자로 바꾼다.

strrev 함수는 문자열을 거꾸로 뒤집는다.

12.1.6 문자 관리 함수

12.1.7 메모리 관리 함수

void *memcpy( void *dest, const void *src, size_t count ) ;

int memcmp( const void *buf1, const void *buf2, size_t count ) ;

void *memchr( const void *buf, int c, size_t count ) ;

void *memsec( void *dest, int c, size_t count ) ;

void *memmove( void *dest, const void *src, size_t count ) ;

   

strcpy에 대응되는 memcpy, strcmp에 대응되는 memcmp 등의 함수들이 있는데 기본적인 동작 방식은 대응되는 문자열 함수와 같다고 생각하면된다. 다만 몇 가지 다른 점이 있는데 메모리 관리 함수들과 문자열 관리 함수들의 차이점은 다음과 같다.

  1. 인수와 리턴값의 타입이 다르다. 문자열 관리 함수들은 항상 문자열을 대상으로 하므로 취하는 인수나 리턴 값이 대부분 char* 형이지만 메모리 조작 함수들은 임의의 값을 대상으로 하기 때문에 인수와 리턴값이 모두 void* 형이다.
  2. 문자열은 시작 번지만 알려 주면 널 종료 문자를 끝으로 인식하기 때문에 길이를 별도로 알려줄 필요가 없다. 하지만 메모리 관리 함수는 길이를 알려 주지 않으면 어디까지가 작업 대상인지를 알지 못한다. 그래서 모든 함수의 끝에 작업 대상의 메모리의 길이를 지정하는 count라는 인수가 있다.

       

int ar1[5] = { 10, 8, 0, 75, 29 } ;

int ar2[5] ;

memcpy ( ar2, ar1, sizeof(ar1) ) ;

메모리 관리 함수는 문자열 관리 함수에 비해 훨씬 더 일반적이다. 문자열 관리 함수는 오로지 char*형만 다룰 수 있지만 메모리 관리 함수는 바이트를 직접 다루기 때문에 모든 타입에 대해 사용할 수 있다.

   

memmove 함수는 메모리의 내용을 지정한 길이만큼 다른 곳으로 옮긴다. 이 함수를 사용하면 배열 중간을 뒤쪽으로 밀어서 빈 공간을 만든 후 그 공간에 다른 내용을 삽입해 넣을 수 있다.

  • 예제 InsertString

#include <stdio.h>

#include <string.h>

   

void main( void )

{

char str[32] = "you are beautiful" ;

char str2[] = "very " ;

   

memmove( str + 13, str + 8, 10 ) ;

memcpy( str+8, str2, strlen(str2) ) ;

   

puts(str) ;

}

memcpy와 memmove는 메모리 내용을 복사한다는 점에서 사실 동일한 함수이다. 그러나 memcpy는 무조건 순방향으로만 복사하는데 비해 memmove는 겹쳐진 메모리에 대해서 원본을 파괴되지 않도록 복사 방향을 지능적으로 선택한다는 점이 다르다.

12.2 수치와 문자열

12.2.1 정수와 문자열

수치와 문자열은 데이터 타입이 다르며 따라서 메모리에 기억되는 모양도 상당히 다르다.

문자열과 수치는 내부적인 모양이 완전히 다르기 때문에 상호 대입하거나 연산할 수 없다.

  • 정수를 문자열로 변환

    char *itoa( int value, char *string, int radix ) ;

    char *itoa( long value, char *string, int radix ) ;

    char * uitoa( unsigned long value, char *string, int radix ) ;

    itoa : Integger to Ascii의 약자

  • 예제 itoa

#include <stdio.h>

#include <string>

   

void main()

{

int num = 12345;

int radix;

char str[32];

   

for( radix = 2; radix <= 20; radix++ )

{

itoa(num, str, radix ) ;

printf("%d진법 : %s\n", radix, str ) ;

}

}

  • 문자열을 정수로 변환

    int atoi( const char *string ) ; // 10진법으로 변환 리턴

    long atol( const char *string ) ; // 10진법으로 변환 리턴

    long strtol( const char *nptr, char **endptr, int base ) ; // base 진법으로 리턴

    unsigned long strtoul( const char *nptr, char **endptr, int base ) ; // base 진법으로 리턴

    atoi : Ascii to Integer의 약자

    0 ~ 9 까지 아리비와 숫자와 +, - 부호 사용 가능

    수치가 아닌 문자열이 전달될 경우 0을 리턴

  • 예제 strtol

#include <stdio.h>

#include <string>

   

void main()

{

char *endptr;

char str[] = "abcd";

   

long l = strtol(str, &endptr, 16);

printf("%x\n", l);

}

12.2.2 실수와 문자열

  • 실수를 문자열로 변환

    char *gcvt( double value, int digits, char *buffer ) ;

    char *ecvt( double value, int count, int *dec, int *sign ) ;

    char *fcvt( double value, int count, int *dec, int *sign ) ;

  • 문자열을 실수로 변환

    double atof( const char* string ) ;

    double strtod( const char *nptr, char **endptr ) ;

12.2.3 sprintf

int sprintf( char *buffer, const char *format, ... ) ;

  • 예제 sprintf

#include <stdio.h>

#include <string>

   

void main()

{

char str[128];

int i = 123;

double d = 3.1415;

   

sprintf(str, "%d", i ) ;

printf("정수를 문자열로 : %s\n", str ) ;

sprintf(str, "%.2f", d ) ;

printf("실수를 문자열로 : %s\n", str ) ;

sprintf(str, "%e", d ) ;

printf("실수를 부동 소수점 형식의 문자열로 : %s\n", str ) ;

}

12.3 문자열 연습

12.3.1 표준 함수 구현

문자열은 배열 형태로 표현되며 배열은 곧 포인터라고 할 수 있음

C 표준 문자열 함수들은 거의 포인터로 구현되어 있음

  • 예제 strfunc

#include <stdio.h>

#include <conio.h>

   

void my_puts( const char *str )

{

while (*str)

{

putch(*str++);

}

putch('\n');

}

   

void my_puts2( const char *str )

{

int i ;

for ( i = 0 ; str[i]; i++ )

{

//putch(str[i]);

printf("%c", str[i]);

}

putch('\n');

}

   

char* my_strcpy( char *dest, const char *src )

{

char *d = dest ;

while( *dest++ = *src++ )

{

}

return d ;

}

   

size_t my_strlen( const char* str )

{

const char *p ;

for( p = str ; *p ; p++ )

{                

}

return p - str ;

}

   

size_t my_strlen2( const char* str )

{

int i ;

   

for ( i = 0 ; str[i] ; i++ )

{

}

return i ;

}

   

char* my_strcat( char* dest, const char *src )

{

my_strcpy(dest + my_strlen(dest), src ) ;

return dest ;

}

   

char* my_strchr( const char *string, int c )

{

while( *string )

{

if ( *string == c )

{

return (char*)string;

}

string++;

}

return NULL;

}

   

char* my_strstr( const char* string, const char *strSearch )

{

const char *s, *sub ;

   

for( ; *string ; string++ )

{

for ( sub = strSearch, s = string ; *sub && *s && *s == *sub ; sub++, s++ )

{

}

if ( *sub == 0 )

{

return (char*)string ;

}

}

return NULL;

}

   

void main( void )

{

char dest[256];

   

my_puts("korea");

my_puts2("한글");

   

my_puts( my_strcpy(dest, "my string copy function test") );

   

printf("my_strlen : %d\n", my_strlen("1234"));

printf("my_strlen2 : %d\n", my_strlen("1223234"));

   

char str[128] = "abcd";

my_puts(my_strcat(str, "efg"));

   

printf("o가 %s습니다.\n", my_strchr("notebook",'o') == NULL ? "없" : "있");

printf("z가 %s습니다.\n", my_strchr("notebook",'z') == NULL ? "없" : "있");

printf("under가 %s습니다.\n", my_strstr("misunderstand","under") == NULL ? "없" : "있");

printf("above가 %s습니다.\n", my_strstr("misunderstand","above") == NULL ? "없" : "있");

}

12.3.2 확장 함수 작성

  • 예제 stradd

#include <stdio.h>

#include <conio.h>

#include <string.h>

   

void stradd( char *str, int c )

{

int len = strlen(str);

str[len] = c;

str[len+1] = 0;

}

   

void main(void)

{

char str[128] = "";

   

stradd( str, 'a' ) ; puts(str);

stradd( str, 'b' ) ; puts(str);

stradd( str, 'c' ) ; puts(str);

stradd( str, 'd' ) ; puts(str);

stradd( str, 'e' ) ; puts(str);

}

  • 예제 stristr

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#include <string.h>

   

char *stristr( const char *string, const char *strSearch )

{

const char *s, *sub ;

   

for ( ; *string ; string++ )

{

for ( sub = strSearch, s = string ; *sub && *s ; sub++, s++ )

{

if ( tolower(*s) != tolower(*sub) )

{

break;

}

if ( *sub == 0 )

{

return (char*)string;

}

}

}

return NULL;

}

   

char *stristr2( const char* string, const char* strSearch )

{

char *scopy, *srchcopy, *p;

   

scopy = (char*)malloc( strlen(string) + 1 );

strcpy( scopy, string );

strlwr( scopy ) ;

srchcopy = (char*)malloc( strlen(strSearch) + 1 ) ;

strcpy( srchcopy, strSearch ) ;

strlwr( srchcopy ) ;

   

p = strstr( scopy, srchcopy ) ;

free( scopy ) ;

free( srchcopy ) ;

   

if( p == NULL )

{

return NULL;

}

else

{

return (char*)string+(p-scopy);

}

   

return NULL;

}

   

void main( void )

{

if( stristr2("madeInKorea","inko"))

{

printf("ok\n");

}

else

{

printf("no\n");

}

}

  • 예제 strreplace

#include <stdio.h>

#include <string.h>

   

void insertstr( char* str, const char *insert )

{

int len ;

   

len = strlen( insert ) ;

memmove( str + len, str, strlen(str)+1 ) ;

memcpy( str, insert, len ) ;

}

   

void deletestr( char *str, int count )

{

memmove( str, str+count, strlen( str + count ) + 1 );

}

   

void strreplace( char *str, const char *a, const char *b )

{

char *p;

   

for ( ;; )

{

p = strstr( str, a );

if ( p == NULL )

{

return ;

}

deletestr(p, strlen(a));

insertstr( p, b ) ;

}

}

   

void main ( void )

{

char str[128] = "welcom to korea" ;

char str2[512] = "내가 그린 기린 그림은 기린 그림";

char *p;

   

puts(str);

p = strstr(str, "korea");

insertstr(p, "beautiful ");

puts(str);

   

p = strstr( str, "to" );

deletestr( p, 3 );

puts(str);

   

puts(str2);

strreplace( str2, "기린", "오랑우탄" );

puts(str2);

}

 

반응형

'책정리 > 혼자 연구하는 C,C++ 1' 카테고리의 다른 글

15장 포인터 고급  (0) 2015.02.19
13장 구조체  (0) 2015.02.19
11장 배열과 포인터  (0) 2015.02.19
10장 포인터  (0) 2015.02.19
9장 배열  (0) 2015.02.19