C 프로그래밍및실습 10. 문자열 세종대학교 목차 1) 문자열이란? 2) 문자열과포인터 3) 문자열의배열 4) 문자열처리함수 5) 문자열및문자입출력 2
1) 문자열이란 문자배열 ( 복습 ) 원소가문자인배열 각배열원소를하나의단위로처리 : 초기화, 입출력 char str[8] = {'H','e','l','l','o'}; // 문자로초기화 int i; for (i=0 ; i<5 ; i++) printf("%c", str[i]); // 문자출력 문자는하나의문자로처리되는경우도있지만, 문자들의묶음을하나로처리하는것이편리한경우가많음 C언어의문자열 3 1) 문자열이란 문자열 (string): 연속적으로나열된문자들의묶음 문자열표현 큰따옴표로감싸서나타냄 예 ) "Hello", "A", "123" 주의 : 'A' 는문자 ( 작은따옴표, 문자열아님 ) 문자열저장 C언어에서문자열은문자배열형태로저장 문자열입출력 scanf, printf에서문자열서식지원 : %s 4
1) 문자열이란 문자열저장및초기화 C언어에서문자열을활용하는기본형태는문자배열 초기화 : 문자열표현방법 ( 큰따옴표를사용 ) 으로초기화 초기화예 char str[8] = "Hello"; // 배열크기지정 char str[ ] = "Hello"; // 배열크기미지정 // 초기화에의해크기결정 5 1) 문자열이란 scanf, printf 를사용한문자열입출력 문자열을하나의단위로취급 서식에 %s 사용하고, 인자로배열의시작주소를전달 char str[8]; scanf("%s", str); printf("%s", str); // 문자열입력 // 문자열출력 scanf에서배열이름은시작주소이므로 & 를안붙여도무방 printf에서서식이 %s인경우에배열에저장된값이아니라배열주소를전달함에유의 6
1) 문자열이란 앞의예제프로그램을문자열처리방식으로바꾸면? char str[8] = {'H','e','l','l','o'}; // 문자로초기화 int i; for (i=0 ; i<5 ; i++) printf("%c", str[i]); // 문자출력 char str[8] = "Hello"; // 문자열로초기화 printf("%s", str); // 문자열출력 7 1) 문자열이란 [ 실습 1] 다음프로그램을작성하시오. 크기가 10인문자배열 str을선언 위배열을선언과동시에문자열 "Hello" 로초기화 문자열 str 을화면에출력 사용자로부터문자열 "World" 를입력받아 str 에저장 문자열 str 을화면에출력 8
1) 문자열이란 널 (null) 문자 문자열의끝을의미하는특수문자로, '\0' 으로표현 널문자의아스키코드값은정수 0, 즉 '\0' == 0 문자열은항상맨마지막에널문자를포함하고있음 ( 명시하지않지만 ) 문자 'A' 와문자열 "A" 의차이 'A' A "A" A \0 9 1) 문자열이란 널 (null) 문자 예 ) 선언문의초기화 char str[] = "Hello"; = char str[] = {'H','e','l','l','o','\0'}; str H e l l o \0 [0] [1] [2] [3] [4] [5] 10
1) 문자열이란 문자로초기화 vs 문자열로초기화 문자로초기화와문자열로초기화시배열의크기비교 char str1[] = {'H','e','l','l','o'}; // 문자로초기화 char str2[] = "Hello"; // 문자열로초기화 printf("%d %d", sizeof(str1), sizeof(str2) ); 결과 : 5 6 str1 str2 H e l l o [0] [1] [2] [3] [4] H e l l o \0 [0] [1] [2] [3] [4] [5] 11 1) 문자열이란 문자배열의크기 문자배열에문자열을저장하기위해서는배열의크기가문자열의길이보다하나더커야함 char str1[6] = "Hello"; char str2[5] = "Hello"; // 정상작동 // 런타임에러유발 H e l l o \0 [0] [1] [2] [3] [4] str2 배열영역벗어남런타임에러의원인 12
1) 문자열이란 printf에서문자열출력 문자열을출력하기위해서는 %s 사용 인자로전달된주소의문자열을출력 char str[20] = "Hello World"; int i; for( i=0 ; i < 20 ; ++i ) printf("%c", str[i]); printf("..\n"); 결과 : Hello World.. char str[20] = "Hello World"; printf("%s..\n", str); 결과 : Hello World.. 배열의크기는 20 인데, 왜 11 자만출력할까? 배열에서초기화가명시되지않은원소는 0 으로초기화됨 '\0' 은화면에공백처럼출력, but 공백문자와는다름 13 1) 문자열이란 printf의 %s 서식과널문자 인자로전달된주소의문자부터널문자전까지출력 배열크기만큼출력하는것이아님 printf 함수는배열의크기를모름 char str[20] = "Hello World"; int i; for( i=0 ; i < 20 ; ++i ) printf("%c", str[i]); printf("..\n"); 결과 : Hello World.. char str[20] = "Hello World"; printf("%s..\n", str); printf("%s..\n", str+5); 결과 : Hello World.. World.. 14
1) 문자열이란 printf의 %s 서식과널문자 ( 추가예 ) %s 서식의기능을 %c서식을사용하여구현하려면? printf("%s", str); = for( i=0 ; str[i] ; ++i ) printf("%c", str[i]); 해당배열원소의값이 참인동안즉, 0 이아닌동안즉, '\0' 이아닌동안 15 1) 문자열이란 printf 의 %s 서식과널문자 ( 추가예 ) char str[20] = "Hello World"; int i; str[7] = '\0'; for( i=0 ; i < 20 ; ++i ) printf("%c", str[i]); printf("..\n"); 결과 : Hello W rld.. char str[20] = "Hello World"; str[7] = '\0'; printf("%s..\n", str); printf("%s..\n", str+5); 결과 : Hello W.. W.. 16
1) 문자열이란 [ 실습 2] 다음프로그램을작성하시오. 크기가 6인문자배열str을선언 사용자로부터문자열 "Hello" 를입력받아 str 에저장 문자열 str 을화면에출력 str[5] 에물음표문자 '?' 대입 문자열 str 을화면에출력 왜이런출력결과가나오는지생각해보자. 17 1) 문자열이란 scanf의 %s 서식과널문자 사용자로부터입력받은문자열을인자로전달된주소부터차례로저장 입력되는문자열끝에널문자를자동으로추가해줌 char str[20]; scanf("%s", str); printf("%s..\n", str); scanf("%s", str+5); printf("%s..\n", str); 실행예시 Hello 입력 Hello.. 출력 World 입력 HelloWorld.. 출력 18
1) 문자열이란 scanf의 %s 서식과널문자 scanf의 %s는개행문자, 공백문자, 탭문자직전까지를하나의문자열로인식 char str[20]; scanf("%s", str); printf("%s..\n", str); 실행예시 Hello World Hello.. 입력 출력 19 1) 문자열이란 주의사항 1 문자배열을문자열로초기화하는것은가능하지만, 문자배열에문자열을대입하는것은불가능 맨아래대입문은 str의시작주소를바꾸라는의미로인식됨 char str[20]; str[0] = 'a'; // 정상 str = "Hello World"; // 컴파일오류 대신, 문자배열에문자열을복사하는기능을하는함수제공 ' 문자열처리함수 ' 에서학습 20
1) 문자열이란 주의사항 2 사용자로부터입력받은문자열을저장할충분한공간이확보되어있어야함 ( 모든배열에공통적인사항 ) char str[5]; scanf("%s",str);... 만약, 사용자가 "HelloWorld" 를입력한다면? 크기가 5 인배열에저장할수없음 배열범위를벗어난메모리영역에입력받은문자저장 런타임에러발생위험 위문자열을저장하기위해서는배열의크기가 11 이상이어야함 ( 왜 10 이상이아니고, 11 이상일까?) 21 목차 1) 문자열이란? 2) 문자열과포인터 3) 문자열의배열 4) 문자열처리함수 5) 문자열및문자입출력 22
2) 문자열과포인터 문자형포인터 : 문자열을활용하는또다른형태 문자열을가리키는포인터 포인터변수 str을선언하고, 문자열 ( 상수 ) "Hello" 를가리키도록초기화해라. str에주소가저장되어있으므로, printf의 %s 서식이용해출력 char *str = "Hello"; printf("%s..\n", str); 0x36 0x20 str 0x20 H e l l o \0 23 2) 문자열과포인터 문자형포인터를배열처럼사용하기 배열과포인터의관계를이용 char *str = "Hello"; for (i=0 ; i<5 ; i++) printf("%c", str[i]); // 문자출력 0x36 0x20 str 0x20 H e l l o \0 24
2) 문자열과포인터 변경가능여부 "Hello" 는문자열상수로, 사용자프로그램에서변경불가능 반면, str은사용자변수로값을변경할수있음 char *str = "Hello"; str[0] = 'h'; // 변경불가능 ( 런타임에러발생 ) str = "World"; // str에저장된값변경 ( 가능 ) 0x36 0x54 str 0x20 상수영역 : 변경불가능 H e l l o \0 0x54 W o r l d \0 25 2) 문자열과포인터 문자배열과문자형포인터비교정리 외우려고하지말고, 메모리그림을그려서이해하자!!! char str[6] = "Hello"; printf("%c", str[0]); // O printf("%s", str); // O char *str = "Hello"; printf("%c", str[0]); // O printf("%s", str); // O str[0] = 'h'; // O str[0] = 'h'; // X scanf("%s", str); // O scanf("%s", str); // X str = "World"; // X str = "World"; // O str H e l l o \0 [0] [1] [2] [3] [4] [5] 0x20 str 0x20 상수영역 : 변경불가능 H e l l o \0 26
2) 문자열과포인터 주의!! str이포인터여서문자변경이안되는것이아님 str이어느영역을가리키는냐에따라달라짐 char arr[6] = "Hello"; char *str = arr; printf("%c", str[0]); // O printf("%s", str); // O 변수영역 : 변경가능 arr str H e l l o \0 [0] [1] [2] [3] [4] [5] 상수영역 : 변경불가능 W o r l d \0 str[0] = 'h'; scanf("%s", str); str = "World"; str[0] = 'w'; scanf("%s", str); // O // O // O // X // X 27 2) 문자열과포인터 [ 실습 3] 다음프로그램을작성하시오. 문자포인터변수 pc를선언하고, 다음문자열로초기화 "To be, or not to be : that is the question" 반복문을사용하여영어소문자 't' 가몇번나오는지출력 28
목차 1) 문자열이란? 2) 문자열과포인터 3) 문자열의배열 4) 문자열처리함수 5) 문자열및문자입출력 29 3) 문자열의배열 여러문자열처리하기 ( 문자배열을여러개사용 ) char num0[5] = "zero"; char num1[5] = "one"; char num2[5] = "two"; printf("%s\n", num0); printf("%s\n", num1); printf("%s\n", num2); num0 num1 num2 z e r o \0 o n e \0 t w o \0 [0] [1] [2] [3] [4] 30
3) 문자열의배열 여러문자열처리하기 ( 문자배열을배열로묶기 ) 2차원문자배열이용 num[0], num[1], num[2] 의자료형은 char * char num[3][5] = {"zero", "one", "two"}; int i; for( i=0; i < 3; ++i ) printf("%s\n", num[i]); num[0] num[1] num[2] z e r o \0 o n e \0 t w o \0 [0] [1] [2] [3] [4] 31 3) 문자열의배열 여러문자열처리하기 ( 문자형포인터를여러개사용 ) char *pnum0 = "zero"; char *pnum1 = "one"; char *pnum2 = "two"; printf("%s\n", pnum0); printf("%s\n", pnum1); printf("%s\n", pnum2); 상수영역 : 변경불가능 pnum0 pnum1 pnum2 z e r o \0 o n e \0 t w o \0 [0] [1] [2] [3] [4] 32
3) 문자열의배열 여러문자열처리하기 ( 문자형포인터를배열로묶기 ) 문자포인터배열사용 char *pnum[3] = {"zero", "one", "two"}; int i; for( i=0; i < 3; ++i ) printf("%s\n", pnum[i]); 상수영역 : 변경불가능 z e r o \0 o n e \0 t w o \0 pnum [0] [1] [2] [3] [4] [0] [1] [2] 33 3) 문자열의배열 [ 실습 4] 다음프로그램을작성하시오. 3x20크기의 2차원문자배열을선언하고, 다음문자열로초기화 "Time is gold" "No pain no gain" "No sweat no sweet" 2 중반복문을사용하여, 각문자열에서영어소문자 'a' 가몇번나오는지출력 ( 추가문제 ) 2 차원문자배열대신문자포인터배열을사용하여구현하시오. 34
목차 1) 문자열이란? 2) 문자열과포인터 3) 문자열의배열 4) 문자열처리함수 5) 문자열및문자입출력 35 4) 문자열처리함수 문자열의길이구하기 1 ( 직접작성 ) 널문자와반복문을이용하여구할수있음 char str[20] = "Hello World"; int i; for( i=0; str[i]!= '\0' ; ++i ) ; printf("length: %d\n", i); 결과 : length: 11 36
4) 문자열처리함수 문자열의길이구하기 2 ( 표준함수이용 ) strlen 함수 원형 : unsigned int strlen(char *s) 기능 : 문자열 s의길이반환 #include<stdio.h> #include<string.h> void main(){ char str[20] = "Hello World"; printf("length: %d\n", strlen(str)); } 결과 : length: 11 37 4) 문자열처리함수 문자열처리표준함수 C언어에서는문자열처리에관련된다양한표준함수제공 대부분 <string.h> 헤더파일에함수의원형선언되어있음 이헤더파일을 include 시켜야함 #include <string.h> 대부분문자열처리함수의코드를작성하는것은어렵지않지만, 이미구현되어있는표준함수를사용하는것이편리 다만, 정확한사용법을익혀야함 38
4) 문자열처리함수 char *strcpy(char *s1, char *s2) 기능 : s1의공간에 s2의문자열복사 ( 문자열대입 ) s2는변화없음 char str1[6] = "Hello"; strcpy( str1, "hi"); printf("str1: %s..\n", str1); 결과 : str1: hi.. str1 H e l l o \0 str1 h i \0 l o \0 [0] [1] [2] [3] [4] [5] [0] [1] [2] [3] [4] [5] strcpy 함수호출전 strcpy 함수호출후 39 4) 문자열처리함수 strcpy(s1, s2) 사용시주의사항 s2의문자열길이 +1 이상의공간이 s1에할당되어있어야함 그렇지않으면, 런타임오류발생 char s1[10], s2[5] = "hi"; char *s3 = NULL; strcpy( s1, s2); // 정상작동 strcpy( s2, "Hello"); strcpy( s3, "Hello"); // 런타임에러유발 // 런타임에러유발 s3 = s1; strcpy( s3, "Hello"); // 정상작동 40
4) 문자열처리함수 char *strcat(char *s1, char *s2) 기능 : s1의문자열뒤에 s2의문자열접합 ( 문자열대입 ) s2는변화없음 char str1[10] = "Hello"; strcat( str1, "hi"); printf("str1: %s..\n", str1); 결과 : str1: hellohi.. str1 H e l l o \0 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] str1 H e l l o h i \0 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] strcat 함수호출전 strcat 함수호출후 41 4) 문자열처리함수 strcat(s1, s2) 사용시주의사항 접합한문자열을저장할수있는충분한공간이 s1에할당되어있어야함 그렇지않으면, 런타임오류발생 char s1[10] = "Hello", s2[5] = "hi", s3[20]; char *s4 = NULL; strcat( s2, s1); strcat( s3, s1); strcat( s4, s1); // 런타임에러유발 // 런타임에러유발 (why?) // 런타임에러유발 42
4) 문자열처리함수 int strcmp(char *s1, char *s2) 기능 : 사전순으로 s1과 s2를비교하여 s1 < s2이면음수, s1 == s2이면 0, s1 > s2이면양수리턴 문자열비교는처음부터문자별로비교 문자비교는아스키코드값을비교함 printf("%d\n", strcmp("hi", "hello") ); 결과 : 1 h i \0 > = h e l l o \0 [0] [1] [2] [3] [4] [5] 43 4) 문자열처리함수 문자열비교예 ( 참고 ) VS에서는 strcmp의리턴값으로음수는 -1, 양수는 1을리턴 char *str = "hi"; printf("%d\n", strcmp(str, "hi") ); printf("%d\n", strcmp(str, "Hi") ); printf("%d\n", strcmp(str, "hi~") ); printf("%d\n", strcmp(str, str) ); printf("%d\n", strcmp("hi", "high") ); printf("%d\n", strcmp("hi", ".") ); 실행결과 0 1 1 0 1 1 44
4) 문자열처리함수 [ 실습 5] 사용자로부터두개의문자열 A와 B를입력받아다음과정을수행하는프로그램을작성하시오. A와 B의길이는 20 이내이고, 공백, 탭, 개행문자는없다고가정 두문자열은서로다르다고가정 1) 문자열 A와 B의길이를각각출력 2) A와 B 중사전순으로빠른문자열출력 3) ABA 형태의새로운문자열 C를생성하고출력 입력예시 welcome helloworld!! 출력예시 7 12 helloworld!! welcomehelloworld!!welcome 45 4) 문자열처리함수 10진수로표현된문자열을수로변환 int atoi(char *s) : int형으로계산하여반환 long atol(char *s) : long형으로계산하여반환 double atof(char *s) : double형으로계산하여반환 <stdlib.h> 에원형선언실행결과 printf("%d\n", atoi("123") ); printf("%d\n", atoi(" 123") ); printf("%f\n", atof(" 123") ); printf("%f\n", atof("123.45") ); 123 123 123.000000 123.450000 46
4) 문자열처리함수 주요문자열처리함수 ( 요약 ) 아래함수의인자에서, s, s1, s2의자료형은 char * 함수원형 unsigned int strlen(s) char *strcpy(s1, s2) char *strcat(s1, s2) int strcmp(s1, s2) 함수기능설명문자열 s의길이리턴문자열 s1에 s2를복사문자열 s1에 s2를접합문자열 s1과 s2를사전순으로비교 int atoi(s) 문자열 (s) 로표현된수를 int형, long atol(s) long형, double형으로계산하여반환 double atof(s) 예 ) atoi("12") 는정수 12 반환 47 목차 1) 문자열이란? 2) 문자열과포인터 3) 문자열의배열 4) 문자열처리함수 5) 문자열및문자입출력 48
5) 문자열및문자입출력 입출력함수 printf 와 scanf : 다양한기능을가진범용입출력함수 함수의크기가크고, 속도느림 C 언어에서는문자열과문자에특화된입출력함수제공 속도빠르고, 문자또는문자열입출력에적합 문자열입출력함수 : puts, gets 문자입출력함수 : putchar, getchar 위함수들은모두 <stdio.h> 에선언되어있음 49 5) 문자열및문자입출력 int puts(char *s) s가가리키는문자열을화면에출력하고, 마지막에 '\n' 출력 출력에성공하면음수가아닌값반환, 실패하면 EOF 반환 EOF (End Of File): 파일의끝을나타내는상수로정수 -1 의값을가짐 char str[10] = "Hi World"; int ret=1; ret = puts(str); printf("return: %d\n", ret); 실행결과 Hi World return: 0 개행문자 '\n' 이출력되어줄이바뀜 위코드에서 puts 대신 printf 를사용하여 str 을출력해보자. 차이점이있는가? 50
5) 문자열및문자입출력 char *gets(char *s) 사용자로부터문자열을입력받아, s가가리키는메모리영역에저장하고, 포인터 s를리턴 엔터 ('\n') 가입력될때까지입력된모든문자들을저장 마지막에입력된 '\n' 은무시하고, 맨뒤에 '\0' 를붙임 문자열을저장할충분한메모리공간이확보되어있어야함 char str[10]; gets(str); printf("str: %s..", str ); 실행예시 Hi World 입력 str: Hi World.. 위코드에서 gets 대신 scanf 를사용하고, 오른쪽의실행예시를수행시켜보자. 어떤차이점이있는가? 51 5) 문자열및문자입출력 ( 참고 ) 보안상의문제로 gets 는표준에서제외됨 Visual Studio의경우 2015 버전부터지원안함 gets_s 사용 (VS에서만쓰는비표준함수 ) 일반적으로는 fgets 함수를사용 이함수에대해서는파일입출력부분에서학습 52
5) 문자열및문자입출력 int putchar(int c) 인자 c의문자를화면에출력 출력에성공하면출력한문자정보리턴, 실패하면 EOF 리턴 EOF (End Of File): 파일의끝을나타내는상수로정수 -1 의값을가짐 int ret = 1; ret = putchar('a'); printf("\nreturn: %d\n",ret); ret = putchar(99); printf("\nreturn: %d\n",ret); 실행결과 a return: 97 c return: 99 53 5) 문자열및문자입출력 int getchar(void) 사용자로부터입력받은문자를리턴 int c; 실행예시 c = getchar(); putchar(c); H H 입력 54