본문 바로가기

Programming/C

[ProjectH4C] 코딩도장 Unit 39~40 Write-Up

문자열

C언어에는 문자 자료형 char가 존재하지만 문자열을 저장하는 자료형은 존재하지 않는다. 그래서 사용하는 방법이 문자열을 배열에 저장한 후에 이를 한번에 입력받아서 각각의 인덱스에 저장하고, 출력할 때도 각각을 연속해서 출력해서 문자열인 것처럼 보이도록 하는 것이다.

C언어에서는 포인터를 배열처럼 구현해서 사용할 수 있는데, 이러한 개념을 가지고 문자열을 다룰 수 있다.

 

#include <stdio.h>

int main()
{
    char c1 = 'a';         // 변수에 문자 'a' 저장
    char *s1 = "Hello";    // 포인터에 문자열 "Hello"의 주소 저장

    printf("%c\n", c1);    // a: %c로 문자 출력
    printf("%s\n", s1);    // Hello: %s로 문자열 출력

    return 0;
}

보통은 char str[] = "Hello" 와 같이 배열에 단어를 넣는데, 이를 포인터를 이용해서 선언해준 것을 볼 수 있다. 실제 출력 결과는 다음과 같다. 이 때, 출력 서식지정자는 %s로 배열을 이용할 때와 동일하다.

 

a
Hello

 

포인터에 문자열을 저장할 때 주의할 점은 문자형 변수를 선언해서 사용할 때는 변수 안에 저장되기 때문에 출력도 가능하고 고쳐쓰는 것도 가능하지만, 포인터는 문자열이 저장되어 있는 곳의 메모리 주소만 저장되어 있기 때문에 문자열을 읽는 것은 가능하지만 수정은 불가능하다. 그리고 C언어에서는 컴파일러가 문자열의 마지막을 널 문자('\0')까지로 인식하기 때문에 s1에 문자열 "Hello"의 주소를 저장했어도 실제로 저장된 값은 "Hello\0" 6개(\0를 하나의 문자로 취급) 문자열의 주소가 저장된다. 그리고 대괄호를 이용해 배열처럼 각각의 문자만 출력할 수 있다. 이 때 역시 수정은 불가능하다.

 

문자열 입력

입력받은 문자열은 배열 형태의 문자열에 저장 가능하다. 정수, 실수 등을 변수에 저장할 때와 같다.

#define _CRT_SECURE_NO_WARNINGS // scanf 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>

int main()
{
    char s1[10];    // 크기가 10인 char형 배열을 선언

    printf("문자열을 입력하세요: ");
    scanf("%s", s1);     // 표준 입력을 받아서 배열 형태의 문자열에 저장

    printf("%s\n", s1);  // 문자열의 내용을 출력

    return 0;
}

서식 지정자는 %s이고, s1은 배열이기 때문에 &s1이 아닌 그냥 s1만 써주면 된다(이름 자체가 주소를 가지고 있기 때문). 이 때, 배열의 크기는 10이지만 문자열을 저장하고 나면 마지막에 널 문자가 들어가야 하기 때문에 사실상 문자열을 저장하는 공간은 최대 9개이고 입력 받은 문자열의 길이의 다음 인덱스에 널 문자가 자동으로 저장된다. scanf는 공백은 입력받지 못하는데, 만약 공백까지 입력하고 싶다면 서식지정자를 %s대신 %[^\n]s로 써주면 공백까지 전부 배열에 저장된다. 하지만 이 역시 문자형 포인터로 선언한 문자열 변수로는 입력받을 수 없다. 포인터 변수에 저장된 메모리 주소는 읽기만 가능하고 쓰기는 불가능하기 때문이다. 그렇기 때문에 문자열 포인터에 값을 입력받고 싶다면, 별도로 원하는 크기만큼 할당 받아서 입력받아야 한다.

 

#define _CRT_SECURE_NO_WARNINGS     // scanf 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>
#include <stdlib.h>    // malloc, free 함수가 선언된 헤더 파일

int main()
{
    char *s1 = malloc(sizeof(char) * 10);    // char 10개 크기만큼 동적 메모리 할당

    printf("문자열을 입력하세요: ");
    scanf("%s", s1);      // 표준 입력을 받아서 메모리가 할당된 문자열 포인터에 저장

    printf("%s\n", s1);   // 문자열의 내용을 출력

    free(s1);    // 동적 메모리 해제

    return 0;
}

위와 같이 작성하면 입력 받고 그대로 출력하는 것까지 문제없이 작동하는 것을 알 수 있다.

 


#39.5 퀴즈

문자열을 선언하는 법은 문자형 포인터로 선언하거나, 문자형 배열에 선언하는 법이다. 배열로 선언할 땐 배열의 크기보다 문자열의 크기가 크면 안된다. 답은 b, e, g, h.

문자열을 출력하는 서식 지정자는 %s이다. 답은 d.

문자를 출력할 땐 %c를 사용한다. 답은 b.

문자열의 끝에 있는 문자를 널 문자라고 하고 기호로는 '\0'로 표시한다. 답은 a, d.

 

 

#39.6 연습문제: 문자열 만들기

 

#include <stdio.h>

int main()
{

   ________________ = "Beethoven 9th Symphony";

   printf("%s\n", s1);

   return 0;
}

출력 예시

Beethoven 9th Symphony

 

문자형 포인터를 사용한다면 char *s1가 되고 배열을 사용한다면 char s[]가 된다.

 

#39.7 연습문제: 문자열 요소 출력

 

#include <stdio.h>

int main()
{
    char s1[30] = "Beethoven 9th Symphony";

    printf("%c\n", _________);

    return 0;
}

출력 예시

9

9는 문자열에서 11번째에 있는 문자이다. 0부터 시작하므로 s[10]을 출력하면 11번째 문자 '9'가 출력된다.

 

 

#39.8 심사문제: 문자열 만들기

#include <stdio.h>

int main()
{
    ________________________

    printf("%s\n", s1);

    return 0;
}

 

출력 예시

Beethoven
9th
Symphony

 

문자열에서 단어 사이사이에 띄어쓰기 대신 '\n'을 써주면 위와 같이 출력된다.

char *s1 = "Beethoven\n9th\nSymphony";

 

 

#40.4 퀴즈

배열은 주소 연산자(&)를 붙이지 않고 사용해야 한다. 답은 c, e, g.

널 문자가 저장될 공간 1개를 제외한 최대 9글자를 저장할 수 있다.

 

#40.5 연습문제: 입력받은 문자열을 배열에 저장하기

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    char s1[10];

    printf("문자열을 입력하세요: ");
    ________________________

    printf("%s\n", s1);

    return 0;
}

출력 예시

문자열을 입력하세요: Hello (입력)
Hello

%s 서식지정자를 이용해서 입력받으면 된다. 답은 scanf("%s", s1);

 

#40.6 연습문제: 입력받은 문자열을 동적 메모리에 저장하기

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

int main()
{
    ①______________________

    printf("문자열을 입력하세요: ");
    ②______________________

    printf("%s\n", s1);

    free(s1);

    return 0;
}

동적 메모리를 사용해야 하기 때문에 malloc 함수를 통해 문자열 포인터를 만들어야 한다.

1. char *s1 = malloc(sizeof(char)*10);

2. scanf("%s", s1);

 

#40.7 연습문제: 문자열 세 개 입력받기

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

int main()
{
    char *s1 = malloc(sizeof(char) * 10);
    char *s2 = malloc(sizeof(char) * 10);
    char *s3 = malloc(sizeof(char) * 10);

    printf("문자열을 세 개 입력하세요: ");
   _________________________________________

    printf("%s\n", s1);
    printf("%s\n", s2);
    printf("%s\n", s3);

    free(s1);
    free(s2);
    free(s3);

    return 0;
}

띄어쓰기로 구분해서 3개의 문자열을 각각 s1, s2, s3에 입력받으면 된다. 답은 sacnf("%s %s %s", s1, s2, s3); .

 

 

#40.8 심사문제: 문자열 네 개 입력받기

문자열 네 개를 저장할 공간을 각각 s1, s2, s3, s4로 동적 할당한다. 띄어쓰기로 구분해서 입력 받은 후에 출력할 때 서식 지정자 사이사이에 '\n'을 써주면 된다.

 

#include <stdio.h>

int main(){
    char *s1 = malloc(sizeof(char) * 30);
    char *s2 = malloc(sizeof(char) * 30);
    char *s3 = malloc(sizeof(char) * 30);
    char *s4 = malloc(sizeof(char) * 30);
    
    scanf("%s %s %s %s", s1, s2, s3, s4);
    printf("%s\n%s\n%s\n%s\n", s1, s2, s3, s4);
    
    return 0;   
}