몇 년전 유행했던 밈이 있다.
이 아저씨를 기억하는가?
난데 없는 "pen", "pineapple", "apple", "pen"을 합쳐 춤추는 영상을 모두 다 기억할 것이다.
오늘은 이 아저씨처럼 문자열의 대입, 붙이기 등을 수행하는 방법에 대해 이야기를 해보려 한다.
컴퓨터에 10+20 식을 넣으면 무심하게 '30' 하고 던질 것이다.
그럼
"pen" + "pineapple" 식 역시 "pen pineapple"하고 던져줄까?
# include <stdio.h> int main(void) { char a[10] = "pen"; char b[10] = "pineapple"; printf("%s\n", a + b); return 0; }
아마 이처럼 실패할 것이다.
문자열로 연산할 때는 문자열 연산에 사용하는 함수
를 따로 사용해야 한다.
char 배열
은 문자열을 저장하는 변수
의 역할을 하며 문자열
로 초기화할 수 있다.
예를 들어, "pineapple" 가 저장된 배열을 "applepen" 로 바꾸려면
char str1[80] = "pineapple"; str1[0] = 'a'; str1[1] = 'p'; str1[2] = 'p'; str1[3] = 'l'; str1[4] = 'e'; str1[5] = 'p'; str1[6] = 'e'; str1[7] = 'n'; str1[8] = '\0';
다음과 같이 문자를 하나씩 대입해야 한다.
그런데 이때 마지막에 널 문자도 저장해야 한다.
널 문자가 빠진 채로 대입하고 끝내면 applepene이 된다.
간단한 문자열이면 괜찮겠지만,
길이가 긴 문자열을 이렇게 대입하는 건 매우 번거롭지 않을까?
라는 질문에
strcpy 함수가 문자열을 한 번에 대입하는 방법으로 제공한다.
strcpy(str1, str2)
str1
: 복사 받을 곳
str2
: 복사할 내용
이런 함수를 문자열 연산 함수
라고 하며 사용하려면 string.h 헤더 파일을 인클루드 해야 한다.
# include <stdio.h> # include <string.h> int main(void) { char str1[10] = "pineapple"; char str2[10] = "applepen"; strcpy(str1, str2); printf("%s\n", str1); return 0; }
쉽다.
strcpy 함수는 복사 받을 곳의 배열명(str1)을 첫 번째 인수로 주고
복사할 문자열(str2)을 두 번째 인수로 준다.
첫 번째 문자부터 널 문자가 나올 때까지 문자를 하나씩 배열에 옮겨 저장하는 방식이다.
# include <stdio.h> # include <string.h> int main(void) { char str1[10] = "pineapple"; char str2[10] = "applepen"; char *ps1 = str2; strcpy(str1, ps1); printf("%s\n", str1); return 0; }
10행처럼 ps1은 str2 배열의 값을 저장한 포인터이므로 문자열의 시작 위치를 알 수 있다.
이처럼 복사할 문자열의 시작 위치를 알 수 있다면 모두 두 번째 인수로 사용할 수 있다.
두 번째 인수는 다양한 값을 사용할 수 있지만 첫 번째 인수로 사용할 수 있는 값은 제한적이다.
첫 번째 인수는 char 배열
이나 그 배열명을 저장한 포인터
만 가능하다.
strcpy("banana", "apple"); strcpy(ps1, "apple");
다음과 같이 문자열 상수는 값을 바꿀 수 없으므로 첫 번째 인수로 사용하면 에러가 발생한다.
문자열 상수를 연결하고 있는 포인터를 사용하는 것도 마찬가지!
strncpy 함수는 strcpy 에서 'n'만 추가된 것이다.
'n' = number
strncpy(str, "applepen", 5);
str
: 복사 받을 배열명
applepen
: 복사할 문자열
5
: 복사할 문자 수
# include <stdio.h> # include <string.h> int main(void) { char str1[20] = "pine apple"; strncpy(str1, "apple-pen", 5); printf("%s\n", str1); return 0; }
결과처럼 strncpy 함수는 복사할 문자열에서 지정한 개수만큼 문자를 복사하고
만약 str 배열이 깔끔하게 문자열 "apple"로만 쓰이도록 하려면
9행에
str1[5] = '\0';
다음 문장을 적어서 널 문자를 추가해야 한다.
깔끔.
이제 "pen", "pineapple", "apple", "pen" 을 붙일 때가 왔다.
배열에 있는 문자열 뒤에 이어 붙일 때는 strcat 또는 strncat 함수를 사용한다.
strcat 함수는 먼저 붙여넣을 배열에서 널 문자의 위치를 찾고
붙여넣기가 끝난 후에는 널 문자를 저장하여 마무리한다.
그럼 이제 붙여보자.
# include <stdio.h> # include <string.h> int main(void) { char str1[50] = "pen"; strcat(str1, "pineapple "); printf("1단계: %s\n", str1); strncat(str1, "apple-pie", 5); printf("2단계: %s\n", str1); strcat(str1, "pen"); printf("최종: %s\n", str1); return 0; }
🔔 11행의 strncat 함수는 strncpy 함수와 달리 붙여넣은 후
널 문자를 저장하여 문자열을 완성한다는 것 챙겨가자!
문자열을 덧붙이는 것이므로 붙여넣기가 되는 배열의 크기가 충분히 커야 한다.
붙여넣을 공간의 주소를 증가시키므로 공간이 부족한 경우
할당되지 않은 다른 메모리 영역을 침범할 수 있다.
붙여넣기 전에 먼저 널 문자의 위치를 찾으므로 초기화되지 않으면
쓰레기 값 중간부터 붙여넣을 가능성이 크다.
따라서, 6행처럼 특별한 문자열로 초기화하거나
다음과 같이 최소한 첫 번째 문자가 널 문자가 되도록 초기화한다.
char str[80] = {'\0'};
char str[80] = {0};
char str[80] = "";
str[0] = '\0';
char 배열은 다양한 길이의 문자열을 저장할 수 있도록 충분히 크게 선언해서 사용한다.
따라서 배열에 저장된 문자열의 길이는 배열의 크기와 다를 수 있는데,
배열에 저장된 문자열의 실제 길이를 알고 싶으면 strlen 함수를 사용한다.
strlen(str)
str
: 크기를 확인할 배열명
# include <stdio.h> # include <string.h> int main(void) { char str1[80], str2[80]; char *resp; // 문자열이 긴 배열을 선택할 포인터 printf("2개의 과일 이름 입력: "); scanf("%s%s", str1, str2); if (strlen(str1) > strlen(str2)) resp = str1; else resp = str2; printf("이름이 긴 과일은: %s\n", resp); return 0; }
strlen 함수는 널 문자가 나올 때까지 문자 수를 세어 반환한다.
문자열의 길이를 반환하므로 11행처럼 반환값을 바로 비교하거나 수식의 일부로 사용한다.
그런데 이런 궁금증이 들 수 있다.
A. sizeof 연산자는 배열에 저장된 문자열 길이와는 상관없이 배열 전체의 크기를 계산한다.
# include <stdio.h> # include <string.h> int main(void) { char str[80] = "apple"; printf("sizeof연산자 출력 결과: %d\n", sizeof(str)); printf("strlen 함수 출력 결과: %d\n", strlen(str)); return 0; }
오늘 함수가 많이 나온다고 당황하지 말고, 포인트 중심으로 기억해보자.
strcmp 함수는 두 문자열의 사전 순서(알파벳 순서)
를 판단하여 그 결과를 반환한다.
strcmp(str1, str2); // str1이 str2보다 사전에 나중에 나오면 1 반환 // str1이 str2보다 사전에 먼저 나오면 -1 반환 // str1과 str2가 같은 문자열이면 0 반환
# include <stdio.h> # include <string.h> int main(void) { char str1[80] = "pear"; char str2[80] = "peach"; printf("사전에 나중에 나오는 과일 이름: "); if (strcmp(str1, str2) > 0) printf("%s\n", str1); else printf("%s\n", str2); return 0; }
strcmp 함수는 두 문자열에서 우선 첫 문자의 아스키 코드 값을 비교한다.
아스키 코드 값이 크면 사전의 뒤에 나오는 문자열이 된다.
대소문자, 숫자 특수문자가 섞인 경우는 반환값이 사전 순서와 다를 수 있다.
비교할 문자 수를 지정할 수 있다는 것!