심화프로그래밍설계 5 Strings 임필옥 1
문자열 문자열 (string literal) : 문자들이 로둘러싸인것. 예 ) "When you come to a fork in the road, take it. "Candy\nIs dandy\nbut liquor\nis quicker.\n --Ogden Nash\n Candy Is dandy But liquor Is quicker. --Ogden Nash 2
3 문자열 printf("when you come to a fork in the road, take it. \ --Yogi Berra"); \ : 2 줄이상을한줄로합치는역할 printf("when you come to a fork in the road, take it. --Yogi Berra"); 가연속으로있으면하나의문자열로취급
4 문자열 abc : 4 개의문자로이루어진배열에저장 : 널문자로이루어진 1 자리배열 컴파일러는문자열을 char * 타입으로다룬다.( 주소 ) a : 포인터사용 a : 정수변수사용
5 char *p; p = "abc"; char ch; ch = "abc"[1]; char digit_to_hex_char(int digit) { return "0123456789ABCDEF"[digit]; }
6 char *p = "abc"; *p = 'd'; /* X */ #define STR_LEN 80 char str[str_len+1]; str[0] ~ str[str_len]
7 char date1[] = "June 14"; /* array */ char *date2 = "June 14"; /* pointer */ 1. date1 : 내용수정가능, date2 : 수정불가 date1[1] = X ; (O) date2[1] = X ; (X) 2. date1 : 배열명 date2 : 문자열을가리키는포인터변수
8 char *p; /* 문자열을위한공간없음 */ char *p; scanf( %s, p) ; /* 실행오류 */ char str[str_len+1], *p; p = str; /* O */ 또는동적할당을해서 p 가가리키도록해야함.
9 char *p; p[0] = a ; p[1] = b ; p[2] = c ; p[3] = d ; /* XXXXXXXXXXX */
문자열출력 char str[] = Are we having fun yet? ; printf("%.6s\n", str); Are we %ms : m 길이보다작으면오른쪽정렬 %-ms : 왼쪽정렬 %m.ps : m 길이중에 p 자리만큼출력 puts(str) : 항상마지막에 new-line 문자추가 10
11 문자형 2 차원배열 char planets[][8] = {"Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto"};
12 문자열배열 char *planets[] = {"Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto"};
<string.h> copying functions 1. void *memcpy(void *restrict s1, const void * restrict s2, size_t n); 2. void *memmove(void *s1, const void *s2, size_t n); 3. char *strcpy(char * restrict s1, const char * restrict s2); 4. char *strncpy(char * restrict s1, const char *restrict s2, size_t n); memcpy 와 memmove 의차이는? memcpy : s1, s2 가겹치는경우에대한처리 undefined memmove : s1, s2 가겹쳐도정상동작 strcpy 와 strncpy : null 문자복사차이 strncpy 는 s2 가 n 보다작으면 s1 의나머지자리를 null 로채운다 13
14 strncpy(str1, str2, sizeof(str1)); /***/ 보다안전한방법 strncpy(str1, str2, sizeof(str1) 1); str1[sizeof(str1)-1] = \0 ; string에대한 strcmp할때기억할점 (ASCII) alpha numeric은연속값대문자는항상소문자보다크기가작다숫자는문자보다작다 space는모든출력가능한문자들보다작다
char source[] = { h, o, t, \0, t, e, a }; char dest[7]; copy 함수 memcpy(dest, source, 3); /* h, o, t */ memcpy(dest, source, 4); /* h, o, t, \0 */ memcpy(dest, source, 7); /* h, o, t, \0, t, e, a */ memmove(dest, source, 3); /* h, o, t */ memmove(dest, source, 4); /* h, o, t, \0 */ memmove(dest, source, 7); /* h, o, t, \0, t, e, a */ strcpy(dest, source); /* h, o, t, \0 */ strncpy(dest, source, 3); /* h, o, t */ strncpy(dest, source, 7); /* h, o, t, \0, \0, \0, \0 */ 15
concatenation 함수 <string.h> char *strcat(char * restrict s1, const char * restrict s2); char *strncat(char * restrict s1, const char * restrict s2, size_t n); comparison 함수 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); char s1[] = { b, i, g, \0, c, a, r }; char s2[] = { b, i, g, \0, c, a, t }; if (memcmp(s1, s2, 7) == 0) /* false */ if (strncmp(s1, s2, 7) == 0) /* true */ 16
search 함수 <string.h> char *strchr(const char *s, int c); void *memchr(const void *s, int c, size_t n); char *strrchr(const char *s, int c); char *p, str[] = Form follows function. ; p = strchr(str, f ); /* 처음 f를찾음 */ p = strchr(p+1, f ); /* 다음 f */ char *p, str[22] = Form follows function. ; /* no null */ p = memchr(str, f, sizeof(str)); 17
<string.h> char *strpbrk(const char *s, const char *s2); char *strstr(const char *s1, const char *s2); char *strtok(char * restrict s1, const char * restrict s2); char *p, str[] = Form follows function. ; p = strpbrk(str, mn ); /* finds first m or n */ p = strstr(str, fun ); /* fun locate */ p = strtok(str, \n ); p = strtok(null, \n ); /* str에서공백 \n으로 token으로분리 */ 18
strtok(s1, s2) 단계 1) strtok : s1 을 s2(delimeter) 를포함하지않는문자열로분리 s1 에서 s2 중하나의문자가나오면, s1 을 null 로마감하고 s1 의시작포인터를반환 단계 2) 두번째 strtok 은 s1 에서남은나머지문자열을계속검색. strtok(null, s2) 동일한문자열 ( 시초의 s1) 로계속검색 주의 : s1 은파괴된다. 19
20 fgets(line, 80, stdin); p = strtok(line, \t\n ); while (p!= NULL) { } p = strtok(null, \t\n ); 예 ) I am a boy. p 는 I, am, a, boy. 을순서대로가리킴
21 str A p r i l 2 8, 1 9 9 8 \0 p = strtok(str, \t ); A p r i l \0 2 8, 1 9 9 8 \0 p = strtok(null, \t, ); A p r i l \0 2 8 \0 1 9 9 8 \0 p = strtok(null, \t ); A p r i l \0 2 8 \0 1 9 9 8 \0
memset/zeromemory void memset(void *s, int c, size_t n); ZeroMemory : C 표준? WinBase.h WinNT.h 에정의 #define ZeroMemory RtlZeroMemory #define RtlZeroMemory(Destination,Length) memset((destination),0,(length)) 22
23 Character Types char : character set 에따라다름 ASCII (American Standard Code for Information Interchange) code : 7-bit, 128 개문자 extened ASCII : 256 개문자 (Latin-1 )
24
<ctype.h> : character int isalnum(int c); /* alphabet + number 면 nonzero 값 return */ int isalpha(int c); /* alphabet */ int isblank(int c); /* blank - \t 와 space. C99 only */ int iscntrl(int c); /* control - \x00 ~ \x1f, \x7f */ int isdigit(int c); /* 10진수 */ int islower(int c); /* 소문자 */ int isprint(int c); /* 출력가능한문자? (white space포함 ) */ int ispunct(int c); /* punctuation.,? */ int isspace(int c); /* white space space, \f, \n, \r, \t, \v */ int isgraph(int c); /* 출력가능한문자? (white space 불포함 ) */ int isupper(int c); /* 대문자 */ int isxdigit(int c); /* 16진수 */ 25
ctype 실습 #include <ctype.h> #include <stdio.h> #define TEST(f) printf( %c, f(*p)? x : ); int main(void) { char *p; printf( alnum cntrl graph print space xdigit\n alpha digit lower punct upper\n ); for (p = zzaz0!\t ; *p!= \0 ; p++) { 26
if (iscntrl(*p)) printf("\\x%02x:", *p); else printf(" %c:", *p); TEST(isalnum); TEST(isalpha); TEST(iscntrl); TEST(isdigit); TEST(isgraph); TEST(islower); TEST(isprint); TEST(ispunct); TEST(isspace); TEST(isupper); TEST(isxdigit); printf("\n"); } return 0; 27
출력 alnum cntrl graph print space xdigit alpha digit lower punct upper a: x x x x x z: x x x x x A: x x x x x x Z: x x x x x 0: x x x x x : x x!: x x x \x09: x x 28
29 문자열 literal 에대한상식 char *p = abc ; char *q = abc p 와 q 를통해내용을변경하지못하도록하는이유는? 1. p와 q가동일한 abc 를가리키고있게하기때문 2. 문자열literal은 Read-only 메모리에저장 문자열 literal의길이 - C89 : 509 문자 - C99 : 4095 문자
30 연습 1 다음프로그램이출력하는값은? char s[] = Hsjodi, *p; for (p = s; *p; p++) --*p; puts(s); ( 프로그램하기전에추측해보자 )
실습 1 함수 int numchar (const char *s, char ch); s 문자열에 ch문자가몇번나오는지반환하는함수 (strchr을사용 ) - 제출 : 함수만제출 ( 함수호출로테스트 ) #define STR_LEN 80 char line[str_len+1]; char ch; scanf( %c, &ch); fgets(line, ); /* line에 80자 */ printf( %d, numchar(line, ch)); 형식으로호출될것을가정. 31
실습 2 공백하나로분리된단어들의연속을입력으로받아반대순서로단어를출력하는프로그램. 입력을문자열 ( 한라인또는최대 1024 문자 ) 로받아들이고, strtok 을사용. 예 ) Enter a series of words: I am a boy. In reverse order: boy. a am I Enter a series of words: today tomorrow In reverse order: tomorrow today (1. 일반 2. recursive call사용 ) 32
33 실습 3 strchr 을연속적으로사용하면문자열에서특정문자가있는위치를모두찾아낼수있다. strrchr 을이용해서뒤에서부터특정문자의위치를 모두찾을수있는지생각해보라. char *p, str[] = Form follows function. ; p = strchr(str, f ); /* 처음 f를찾음 */ p = strchr(p+1, f ); /* 다음 f */
34 실습 4 if ( ch == a ch == b ch == c ) 이문장을 strchr 을이용하여간단히하여라. char *strchr(const char *s, int c);
35 실습 5 공백, tab,new-line 으로분리되는단어의숫자를세는함수 int count_words(char *sentence); 작성 strtok을사용, 단어의개수를반환. 함수만제출
36 실습 6 void remove_filename(char *url); 입력 : http://www.knking.com/index.html 출력 : http://www.knking.com 마지막 / 와다음의화일명을삭제문자열함수사용하지않는버전과사용하는버전 2가지
프로그램해독연습 int f(char *s, char *t) { char *p1, *p2; 이함수가하는일은무엇일까? for (p1 = s; *p1; p1++) { for (p2 = t; *p2; p2++) if (*p1 == *p2) break; if (*p2 == \0 ) break; } return p1 s; } f( abcd, babc ) ; 3 f( abcd, bcd ); ; 0 이나온다. 37
38 계산기오류들 1) 실행오류 : 답이 linux에서해서오류가나는경우 : 로직이이상해서오류가나는경우 2) 123a 456 + = 해도결과값이제대로나오는경우. 3) 문제오해 4) = 없이처리 5) 반복안함 6) 코멘트없거나형식적인코멘트 7) 분리파일잘못구성 8) C표준안지킴
39 과제 (RPN 계산기 ) 평가기준 항목 배점비율 비고 소스분리 10 실행완성도 50 문제요구사항준수 10 - 입력양식 - =, q. 적절한코멘트 10 오류처리 5 표준화준수 5 기타 ( 소스정리등등 ) 10 기한준수 마감후 1일 10% 감점
scanf( %[^\n], line); scanf 계열 : \n이나올때까지다읽어서 line에넣기 : 공백문자까지읽을수있다. scanf( %[^6], line); : 6가나올때까지읽어라. 40
41 scanf 실습 char line[128]; scanf( %[^\n], line); printf( 1. line = [%s] \n, line); scanf( %[^6], line); printf( 2.line = [%s] \n, line); scanf( %[^\n], line); printf( 3.line = [%s] \n, line); 입력을 123 456 789 를 2 줄입력해보자 결과는??
scanf( %3d, &age); scanf 입력 : 1234 age 에는 123 만들어감. scanf( %3d, &age); scanf( %d, &len); 입력 : 1234 age에 123, len에 4 그러므로 scanf 할때는최대숫자를넣지않는게편리 42
43 int i, j; char s[100]; scanf scanf( %d%s%d, &i, s, &j); 입력 : 12abc34 56def78 을하면 i, s, j 에들어가는값은? i = 12, j = 56, s = "abc34"