티스토리 뷰

C, C++

[ C언어 ] 14. 문자열

RiKang 2017. 12. 4. 23:06
반응형
Table of Contents

 

개요

문자열의 입출력

NULL 문자

gets() 와 puts()

strlen()

문제

 

 

 

1. 개요

 

 char 들의 배열로 사용되는 '문자열'은, int 나 float 등의 배열과 조금 다른 특성과 쓰임을 가지고 있습니다. 이에 따라 C언어에서는 문자열에 사용할 수 있는 서식문자나 함수등 여러 가지 요소들을 제공하고 있으며, 이 글에서는 이런 문자열에 대해 소개하고 있습니다. 변수형 char에 대해 기억이 나지 않으신다면 char 설명 을 보고 오시는 걸 추천합니다.

 

 

 

2. 문자열의 입출력

 

 1. 기본 입출력

 

 배열의 원소 하나하나에 입력을 받는 int 배열과 달리 문자열은 한번에 입력, 출력을 할 수 있습니다. 대표적인 형식은 아래와 같습니다.

 

1
2
3
//code by RiKang, weeklyps.com
scanf("%s",문자열의 주소);
printf("%s",문자열의 주소);
cs

 

 문자열의 주소는 어렵게 생각할 것 없는 것이, char 배열을 선언하면 배열의 이름이 곧 문자열의 주소를 의미하게 됩니다.

 

1
2
3
4
5
6
7
8
9
//code by RiKang, weeklyps.com
#include <stdio.h>
 
int main(void) {
    char a[105];
    scanf("%s",a);
    printf("%s",a);
    return 0;
}
cs

 

입력 : as;sdf\\ad -> 출력 : as;sdf\\ad

 

 변수의 이름과 달리 배열의 이름은 그 자체로 주소를 나타내기 때문에, 변수를 입력 받을 때와 달리 &를 쓰지 않는다는 점을 주의하시길 바랍니다.

 

2. scanf("%s",문자열의 주소);

 

 scanf 에서 %s를 사용하면, 입력에 띄워 쓰기나 줄 바꿈(엔터)이 들어올 때까지 문자열을 입력 받습니다. 따라서 아래와 같은 프로그램을 코딩하시고 "let me"라는 입력을 넣어 보시면, a 에는 "let", b에는 "me" 가 들어간다는 걸 확인하실 수 있습니다.

 

1
2
3
4
5
6
7
8
9
10
//code by RiKang, weeklyps.com
#include <stdio.h>
 
int main(void) {
    char a[105];
    char b[105];
    scanf("%s %s",a,b);
    printf("a : %s\nb : %s",a,b);
    return 0;
}
cs

 

입력 : let me -> 출력 : a : let\nb : me

 

1
2
3
4
5
6
7
8
9
10
//code by RiKang, weeklyps.com
#include <stdio.h>
int main(void) {
    char a[105], b[105], c[105];
    scanf("%s%s%s",a,b,c);
    printf("%s\n",a);
    printf("%s\n",b);
    printf("%s\n",c);
    return 0;
}
cs

 

입력 : i am fine -> 출력 : i\nam\nfine

 

3. 문자열의 주소의 다른 표현

 

 문자열의 주소는 첫 번째 문자의 주소, 즉, a[0] 의 주소와 일치합니다. 따라서 아래와 같이 입력하여도 똑같이 실행 가능합니다.

 

1
2
3
4
5
6
7
8
//code by RiKang, weeklyps.com
#include <stdio.h>
int main(void) {
    char a[105];
    scanf("%s",&a[0]);
    printf("%s\n",&a[0]);
    return 0;
}
cs

 

입력 : ace -> 출력 : ace

 

 또한 아래와 같은 식으로 문자열의 주소를 다른 주소로 잡으면 중간부터 출력 되기도 합니다.

 

1
2
3
4
5
6
7
8
//code by RiKang, weeklyps.com
#include <stdio.h>
int main(void) {
    char a[105];
    scanf("%s",&a[0]);
    printf("%s\n",&a[1]);
    return 0;
}
cs

 

입력 : ace -> 출력 : ce

 

3. 문자열 초기화

 

 문자열에 원하는 값을 넣어주고 싶다면, 배열에 초기값을 넣는 것처럼 {문자, 문자, ...} 의 형식도 가능하고, "문자열"의 형식도 가능합니다.

 

1
2
3
4
5
6
7
8
9
10
//code by RiKang, weeklyps.com
#include <stdio.h>
 
int main(void) {
    char a[105]={'t','a','d','s',};
    char b[105]="tads";
    printf("%s\n",a);
    printf("%s",b);
    return 0;
}
cs

 

 문자 변수 하나를 쓸 때는 작은 따옴표를, 문자열을 쓸 때는 큰 따옴표를 사용합니다.

 

 다음으론 배열의 크기를 지정해주지 않는 경우입니다. 이때는, 입력해준 문자의 개수에 따라 컴파일러가 알아서 크기를 설정하도록 되어있습니다.

 

1
2
3
4
5
6
7
//code by RiKang, weeklyps.com
#include <stdio.h>
int main(void) {
    char a[]="ace";
    printf("%s\n",a);
    return 0;
}
cs

 

 

 

3. NULL 문자

 

 C언어의 문자열에는 마지막 문자 다음에 NULL 문자 (아스키 코드값 0) 가 들어간다는 약속이 있습니다. 이로 인해, 컴파일러 입장에서는 문자열을 앞부터 순서대로 읽다가 중간에 NULL 문자가 나오면, "문자열이 끝났구나!"라는 걸 알 수 있습니다.

 

 한 번 아래와 같은 문자열을 생각해 보겠습니다.

 

 

 얼핏 보면, 8개의 문자가 들어간 문자열로 처리할 것 같지만, 출력해보면 "ace"가 출력됩니다. 컴파일러가 NULL을 만나자마자 문자열이 끝났다고 판단하고, 결국 첫 번째 NULL 뒤에 있는 변수들은 비어있는 셈 치기 때문이지요.

 

1
2
3
4
5
6
7
8
//code by RiKang, weeklyps.com
#include <stdio.h>
 
int main(void) {
    char a[105]={'a','c','e',NULL,'b''d'NULL'a', };
    printf("%s\n",a);
    return 0;
}
cs

 

-> 출력 : ace

 

 문자열의 끝에는 이 NULL 문자가 반드시 있어야 합니다. 따라서 문자 3개를 저장할 문자열이라고 해도, char a[3]; 이런 식으로 선언하면 에러가 날 수 있습니다. NULL 문자가 들어갈 자리가 없기 때문입니다. 이로 인해 문자열을 선언할 때에는 저장할 문자열의 최대 길이 + 1 정도의 여유를 두는 것이 일반적입니다.

 

1
2
3
4
5
6
7
8
9
//code by RiKang, weeklyps.com
#include <stdio.h>
int main(void) {
    char a[3]="ace";
    char b[4]="ace";
    printf("%s\n",a); // NULL 이 없기 때문에 제대로 처리가 안될 수 있다.
    printf("%s\n",b);
    return 0;
}
cs

 

 

 

4. gets() 와 puts()

 

 scanf() 와 printf() 이외에도 문자열을 입출력 할 수 있는 함수들이 존재하는데, 이 곳에서는 그 중 gets()와 puts()를 소개합니다.

 

gets(문자열의 주소);

 

 gets를 위와 같이 사용하면, 줄 바꿈(엔터)가 들어오기 전까지 문자열을 입력 받습니다. 즉, scanf에서 %s로 입력받을 떄와 달리 띄워 쓰기도 문자열에 포함됩니다.

 

puts(문자열의 주소);

 

 문자열을 출력하고 줄 바꿈을 합니다. printf() 는 \n 을 써주지 않으면 줄 바꿈을 하지 않는다는 점에서 차이점을 보입니다.

 

1
2
3
4
5
6
7
8
9
//code by RiKang, weeklyps.com
#include <stdio.h>
 
int main(void) {
    char a[105];
    gets(a);
    puts(a);
    return 0;
}
cs

 

입력 : let me introduce my self -> 출력 : let me introduce my self\n

 

1
2
3
4
5
6
7
8
9
//code by RiKang, weeklyps.com
#include <stdio.h>
 
int main(void) {
    char a[105];
    scanf("%s",a);
    printf("%s",a);
    return 0;
}
cs

 

입력 : let me introduce my self -> 출력 : let

 

 위의 두 프로그램을 만들어 놓고 여러 가지 입력을 넣어보시면 차이점을 보다 명확히 알 수 있습니다.

 

 

 

5. strlen()

 

 strlen() 은 문자열의 길이를 반환해주는 함수입니다.

 

strlen(문자열의 주소);

 

 이 strlen 함수는 이전에 쓰인 함수들과 달리 stdio.h 가 아니라 string.h 에 저장되어 있기 때문에, strlen 을 쓰기 위해서는 전처리문 #include <string.h> 을 꼭 써주어야 합니다. 일단 아래의 코드를 따라 해보겠습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
//code by RiKang, weeklyps.com
#include <stdio.h>
#include <string.h>
 
int main(void) {
    char a[105];
    scanf("%s",a);
    int b;
    b=strlen(a);
    printf("a의 길이 : %d",b);
    return 0;
}
cs

 

입력 : let -> 출력 : a의 길이 : 3

 

입력 : introduce -> 출력 : a의 길이 : 9

 

 strlen 은 길이를 반환하기 때문에, 이와 같이 정수형 변수를 통해 그 값을 저장할 수 있습니다. 또한 이를 활용해 문자열을 순회하는 것이 가능합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//code by RiKang, weeklyps.com
#include <stdio.h>
#include <string.h>
 
int main(void) {
    char a[105];
    scanf("%s",a);
    int b;
    b=strlen(a);
    for(int i=0; i<b; i++){
        printf("a의 %d 번째 문자 : %c\n", i, a[i]);
    }
    return 0;
}
cs

 

 아래와 같은 형식도 가능합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
//code by RiKang, weeklyps.com
#include <stdio.h>
#include <string.h>
 
int main(void) {
    char a[105];
    scanf("%s",a);
    for(int i=0; i<strlen(a); i++){
        printf("a의 %d 번째 문자 : %c\n", i, a[i]);
    }
    return 0;
}
cs

 

 strlen 함수는 , scanf 나 printf 와 달리 무언가를 반환해주는 함수이며, 따라서, 그 반환값을 받지 않고 그대로 두면 에러가 발생합니다.

 

1
2
3
4
5
6
7
8
9
10
//code by RiKang, weeklyps.com
#include <stdio.h>
#include <string.h>
 
int main(void) {
    char a[105];
    scanf("%s",a);
    strlen(a);
    return 0;
}
cs

 

 strlen(a)는 정수형 변수를 반환하는데, 그걸 어떠한 형태로도 사용하지 않았기 때문에 에러가 발생하는 것이지요. 결국 아래의 코드가 에러가 나는 이유와 비슷한 원리라고 볼 수 있습니다.

 

1
2
3
4
5
6
7
8
9
//code by RiKang, weeklyps.com
#include <stdio.h>
#include <string.h>
int main(void) {
    char a[105];
    scanf("%s",a);
    3;
    return 0;
}
cs

 

 

 

6. 문제

 

 

백준 온라인 저지 채점 방법

 

 

 

(0) [BOJ 11654] 아스키 코드

 

 

 

(1) [BOJ 11721] 열 개씩 끊어 출력하기

 

 

 

(2) [BOJ 10808] 알파벳 개수

 

 

 

(3) [BOJ 10987] 모음의 개수

 

 

 

(4) [BOJ 1157] 단어 공부

 

 

 

(5) [BOJ 8958] OX퀴즈

 

 

 

(6) [BOJ 2675] 문자열 반복

 

 

 

(7) [BOJ 10173] 니모를 찾아서

 

 

 

(8) [BOJ 10798] 세로읽기

 

 

 

(9) [BOJ 11655] ROT13

 

 

 

풀이 모음

 

 

반응형

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

[ C언어 ] 16. 포인터  (0) 2018.01.02
[ C언어 ] 15. 형 변환  (0) 2017.12.07
[ C언어 ] 13. 연산자 우선순위  (0) 2017.11.27
[ C언어 ] 12. 배열  (0) 2017.11.25
[ C언어 ] 11. 이진수와 비트연산자  (0) 2017.11.23