728x90
반응형

부스트코스 cs50 c언어 문자열에 대한 강의를 듣고 정리하려고 한다.

 

지난 강의에서는 C언어 기초인 기본 문법과 사용법에 대해서 공부했었다.
이번 글에서는 C언어에서 문자열을 다루기 위해 어떻게 사용하는지에 대해서 알아보았다.
이번 강의에서는 사용자로부터 문자열을 입력받고 다른 문자열과 합쳐서 출력하는 프로그램에 대해 설명해주고 있다.

 

문자열 입력

스크래치에서는 ask 란 블록과 say 라는 블록을 합쳐 문자열을 입력받고 말하는 기능을 만들었었다.
그럼 ask 블록과 같이 문자열을 입력받아 say 블록과 같이 문자열을 출력해주는 프로그램을 만들어보자.

 

지난 시간에 say 블록은 printf 라는 함수를 통해 문자열을 출력해주었다.
그래서 printf 를 통해 hello, world 라는 문자열을 출력해보는 프로그램을 만들었었다.

 

이번에는 문자열을 입력받아 다른 문자열과 합쳐서 출력하는 프로그램을 만들어보았다.

 

CS50 Sandbox 에서는 get_string 함수를 통해 문자열을 출력하고 문자열을 입력할 수 있게 해주는 함수다.
CS50 라이브러리를 통해 사용할 수 있는 함수이기 때문에 아래와 같이 사용해볼 수 있다.

#include <stdio.h>

// cs50 헤더파일 추가
#include <cs50.h>

int main(void) {
    get_string("What's your name?\n");
}

 

get_string 함수는 cs50 라이브러리에서 지원해주는 함수이기 때문에 상단에 다음과 같이 헤더파일을 추가해서 사용해줘야 한다.

 

이전 글에서도 말했듯이 컴파일 전에 cs50.h 헤더파일을 가져와 cs50.h 안에 있는 함수를 컴파일할 수 있게 해준다.
cs50.h 헤더파일에는 실제로 구현되어있는 함수가 들어있다.

 

 

컴파일 에러에 대해서 (clang 명렁어 컴파일 에러 및 make 명령어 사용)

그런데 헤더파일을 추가하고 컴파일을 진행했더니 다음과 같이 에러가 발생했다.

$ clang -o string2 string2.c
/tmp/string2-5228bb.o: In function `main':
string2.c:(.text+0x19): undefined reference to `get_string'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

 

clang 명령어를 통해 컴파일을 진행했다.
-o string2 부분은 -o 옵션을 통해 머신코드의 이름을 지정해줄 수 있다.
string2 라는 이름으로 머신코드를 생성하라는 것이다. cs50.h 라는 헤더파일도 추가해주었는데 왜 에러가 발생했을까?

 

소스코드에서 두 가지 명심해야할 것이 있는데
하나는 사용하는 함수가 들어있는 헤더 파일을 추가해야하는 것이고 다른 하나는 사용하는 함수가 들어있는 헤더파일을 상단에 include 를 통해서 추가했으니까 컴파일할 때 당연히 추가되었다고 생각하고 잘 되겠지 라고 생각할 수 있다.
하지만 코드를 컴파일할 때 아까와는 다른 이유로 다시 한번 컴퓨터에게 cs50.h 헤더 파일에 있는 get_string 함수나 문자열 같은 것들을 구현하는 모든 코드를 추가하도록 해야한다고 한다.
cs50 에 작성된 함수 역시 c언어 만들어졌고 클라우드 내부에서 소스코드 또한 따로 존재할 것이다.
따라서, 두 가지 코드가 한 프로그램에서 실행될 수 있도록 연결시켜줘야 한다는 것이다.

 

따라서 다음과 같이 내가 작성한 소스코드와 함수가 작성되어 있는 소스코드를 연결시켜줄 수 있다.

$ clang -o string string.c -lcs50 

 

-lsc50 이라는 옵션을 통해 cs50 을 연결시켜주었다.
-l 옵션은 link, 즉 소스코드를 연결시켜주는 옵션이다.

 

그럼 여러 코드를 추가해서 프로그램을 만든다면 그만큼 여러 소스코드들을 연결시켜 컴파일을 진행해야 한다.
복잡한 과정이기 때문에 다음과 같이 make 명령어를 통해서 쉽고 간단하게 컴파일할 수 있다.

$ make string
clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow    string.c  -lcrypt -lcs50 -lm -o string

 

자세히 들여다보니 make 라는 명령어가 clang 명령어를 통해 자동으로 옵션을 부여해 컴파일을 해준다는 것을 확인할 수 있다.
아까 사용했었던 -lcs50 이란 옵션도 추가가 되어있는 것을 확인했고 -o 옵션을 통해 string 이름으로 머신코드를 생성하는 것을 확인할 수 있었다.

 

여기서 주의해야 할 점은 소스코드 이름을 적는 게 아니라 프로그램 이름을 적는 것이다.
예를 들어, string.c 를 컴파일하려면 make string 명령어를 통해 string.c 소스코드를 찾아 컴파일해준다.

 

추가로 make 명령어는 ls, cd 명령어과 같이
유닉스, 리눅스 운영체제에서 사용하는 일반적인 명령어라고 한다.

 

 

변수 생성 및 저장(할당)

그럼 입력한 문자열을 입력받아 저장할 변수를 만들어보자. 변수 이름은 내 마음대로 만들 수 있다.
여기서 유의해야할 점은 단순히 변수 이름만 써주는 것이 아니라 변수의 데이터 타입을 정확하게 명시해주어야 한다는 것이다.

 

지금 저장할 변수는 문자열(string)이기 때문에 string 타입이라고 변수 이름 앞에 지정해주어야 한다.

 

C 언어에서는 문자열 말고도 다른 타입이 있다.
정수형(int), 실수형(float, double) 등 다양한 데이터 타입이 있기 때문에 저장할 데이터가 어떤 타입이 정확하게 명시해주어야 한다.

// 문자열 타입 answer
string answer;
// 정수 타입 number
int number;
// 실수 타입 pi
float pi;

 

이렇게 데이터 타입을 지정해 변수를 생성할 수 있다.

 

그럼 입력받은 문자열을 다음과 같이 변수에 저장해줄 수 있다.

string answer = get_string("What's your name?\n");

 

string 문자열 타입으로 answer 라는 변수를 만들었고 등호(=) 를 적고 get_string 함수를 통해 입력받은 문자열을 answer 변수에 저장하려고 한다.

 

여기서 처음 프로그래밍 언어에 대해서 배우게 되면 헷갈리는 부분이 생기게 된다.

 

등호(=) 표시는 일반적으로 같다는 뜻으로 사용한다.
하지만 프로그래밍 언어에서는 같다는 뜻이 아닌 오른쪽에서 왼쪽으로 가는 화살표라고 생각하면된다.

 

string answer  ←  get_string()

 

다시 말해, 오른쪽에 있는 값을 왼쪽에 있는 변수에 저장 하라는 것이다.
등호(=) 는 할당 연산자라고 부른다.

 

그럼 위의 내용을 설명하자면
get_string 함수를 통해 입력받은 문자열을 answer 라는 문자열 타입의 변수에 저장한다는 것이다.

 

 

변수에 저장된 문자열 출력

그럼 변수 안에 저장된 값을 어떻게 출력할 수 있을까?

 

이전 강의에서는 문자열을 출력할 때 printf 함수를 통해 출력했다.
이번에도 printf 함수를 통해 변수를 출력해보자.

#include <stdio.h>
#include <cs50.h>

int main(void) {
    string answer = get_string("What's your name?\n");
    printf("hello, answer\n");
}

 

이렇게 작성해보았다. 결과를 출력해보니 다음과 같이 나왔다.

$ ./string
What's your name?
jaynam
hello, answer

 

변수 안에 저장된 값이 나오는 것이 아니라 변수 이름이 출력되었다.

 

당연한 결과다. printf 함수에서 큰따옴표 안에 있는 문자열을 그대로 출력하게 한다. 그래서 적은 그대로 출력되는 것이다.

 

answer 라는 변수 안에 저장되어 있는 값을 출력하려면 어떻게 해야할까?

 

데이터 타입에 맞게 변수를 출력할 수 있게 도와주는 형식 지정자 를 통해 변수 안에 저장된 값을 출력할 수 있다.
형식 지정자는 퍼센트(%) 를 통해 출력할 수 있다
문자열 타입 string 은 %s 로 사용할 수 있고 그 외에도
정수 타입 int 는 %d (sgined int), 실수 타입 float, double 은 %f (float) , %lf (long float) 등 
다양한 데이터 타입을 표현할 수 있게 도와준다. 추가로 설명하자면 데이터 타입은 출력할 수 있는 데이터 크기가 다르다.
따라서 데이터 크기의 범위를 넘어가게 되면 출력이 되지 않기 때문에 데이터의 크기에 따라서 변수의 데이터 타입을 지정해주어야 한다.

 

지금 answer 는 문자열 타입(string)이기 때문에 문자열을 출력해야 한다.
따라서 %s 로 문자열을 받아 printf 함수에서 출력할 수 있다. 형식 지정자는 아래와 같이 사용할 수 있다.

#include <stdio.h>
#include <cs50.h>

int main(void) {
    string answer = get_string("What's your name?\n");
    
    // 형식지정자를 사용해서 문자열 타입의 변수 값 출력
    printf("hello, %s.\n", answer);
}

 

그럼 이제 출력을 해보자.

$ ./string
What's your name?
nam jay
hello, nam jay.

 

입력받은 문자열이 변수를 통해 제대로 출력된 것을 확인할 수 있다.

 

여기까지 문자열을 입력 받아 변수에 저장하고 변수를 통해서 출력하는 과정까지 정리해보았다.
추가적으로 cs50 라이브러리를 사용하지 않고 문자열을 입력받고 출력할 수 있는지에 대해서도 공부해야겠다.

 

 

 

- 참고 사이트 -

www.boostcourse.org/cs112/lecture/119005

 

모두를 위한 컴퓨터 과학 (CS50 2019)

부스트코스 무료 강의

www.boostcourse.org

dojang.io/mod/page/view.php?id=736

 

C 언어 코딩 도장: 85.2 서식 지정자

printf, sprintf, fprintf에서 사용하는 서식 지정자(format specifier)는 다양한 활용법이 있습니다. 다음은 기본 서식 지정자이며 정수, 실수, 문자, 문자열, 포인터의 메모리 주소를 출력하는 기본 서식

dojang.io

 

 

728x90
반응형
복사했습니다!