본문 바로가기

CS50

2. C 언어

모두를 위한 컴퓨터 과학(CS50 2019) 강의를 듣고 요약한 내용입니다. 해당 글에는 퀴즈에 대한 정답 및 풀이도 있습니다. 아직 퀴즈를 풀지 못하신 분들은 퀴즈를 풀고 난 후에 해당 포스팅을 읽으시길 바랍니다.

 

목차

1) C 기초

2) 문자열

3) 조건문과 루프

4) 자료형, 형식 지정자, 연산자

5) 사용자 정의 함수, 중첩 루프

6) 하드웨어의 한계

 

 


1. C 언어 - C 기초

학습 목표: C로 "hello, world"를 출력하는 프로그램을 만들 수 있습니다.

 

C 언어

- C는 아주 오래되고 전통적인 순수 텍스트 기반의 언어
- 검은 색 바탕에 있는 이상한 글씨들은 아래의 스크래치 블록과 결과적으로 정확히 같습니다.

 

 

- #include <stdio.h> 는 "stdio.h"라는 이름의 파일을 찾아서 "printf" 함수에 접근할 수 있도록 해줍니다.

- int main(void) 는 "초록색 깃발을 클릭했을 때" 블록과 같은 역할을 합니다. 

- printf("hello, world\n")은 스크래치의 "'hello, world'라고 말하기" 블록과 같은 역학을 합니다.

- 글자나 단어, 문장을 적을 때는 텍스트에 쌍따옴표로 감싸야 합니다.

- C에서 코드가 끝날 때는 세미콜론을 붙입니다.

- \n 은 줄바꿈(개행)을 의미합니다.

 

 

컴파일러

- 우리가 직접 작성한 코드: 소스 코드

- 2진수로 작성된 코드: 머신 코드

- 소스 코드를 머신 코드로 변환해야 컴퓨터가 우리의 소스 코드를 실행할 수 있습니다.

- 소스 코드를 머신 코드로 변환해주는 프로그램: 컴파일러

 

 

- 터미널 창의 명령어 프롬프트에서 "$" 기호 옆에 우리가 원하는 명령어를 입력하면 됩니다.

- clang hello.c 라는 명령어는 "clang" 이라는 컴파일러로 "hello.c" 라는 코드, 파일을 컴파일 하라는 의미입니다.

- 그 결과 a.out 이라는 파일이 생성됩니다. (a.out 이라는 파일 이름이 마음에 들지 않으면 clang -o "마음에 드는 이름" hello.c 를 입력하고 실행시켠 됩니다.)

- 터미널 창의 명령어 프롬프트에서 ./a.out 이라는 명령어를 실행하면 컴퓨터가 현재 디렉토리에 있는 a.out 이라는 프로그램을 실행하게 해줍니다.

 

 

 


2. C 언어 - 문자열

학습 목표: C로 문자열 형식을 가진 변수를 선언하고 출력하는 프로그램을 만들 수 있습니다.

 

실습

- String(문자열)은 단어, 구절, 문장, 알파벳 글자들이 쌍따옴표에 들어가 있습니다.(숫자와는 다른 종류의 데이터)

- 왼쪽 사진을 아래와 같이 C 언어로 작성해보겠습니다.

 

 

- 사용자의 이름을 받아서 저장할 변수를 answer 라고 정해보겠습니다.(answer라는 글자 외에 다른 문자가 와도 괜찮습니다)

- C 언어는 변수가 저장하는 데이터의 종류를 정확하게 명시해야 합니다.

- answer 라는 변수에 담기는 값의 종류가 문자열이라는 것을 명시하기 위해 string 을 붙여줍니다.

 

- 프로그래밍 언어에서 = 는 오른쪽에 있는 것을 왼쪽에 있는 것에다가 지정한다는 의미

- = 는 할당 연산자 

- get_string 함수가 사용자의 이름을 반환하면 그 이름을 answer 라는 변수에 저장합니다.

 

 

- printf 함수는 뭔가를 화면 상에 출력하고 싶을 때 사용하는 함수

- printf("hello, %s\n", answer) 에서 괄호 안의 내용물을 인자 혹은 매개 변수라고  하며 우리의 입력이 들어가는 것입니다. 

- answer 값을 활용해서 출력 시, printf("hello, answer") ❎, printf("hello, %s\n", answer) 🅾️

- 입력하고자 하는 값이 문자열이라면 모든 형식 지정자에 %s 가 필요합니다.

 

 

- 현재 단계에서는 문자열이라는 것이 C 에 없습니다. 

- 문자열은 이 강의가 제공하는 cs50.h 라는 파일 안에 있습니다. 

- stdio.h 에서 printf 함수를 가져온 것처럼 문자열, get_string 함수에 대한 정의가 cs50.h 라는 파일 안에 있습니다.

- 위 코드를 컴파일할 때 나타났던 문제의 원인은 문자열이 뭔지 컴퓨터가 몰랐기 때문입니다. get_string 함수가 무엇인지 몰랐기 때문입니다.

 

 

- cs50 라이브러를 사용할 때는 두 가지를 명심해야 합니다.

- 먼저 소스코드에서는 #include <cs50.h> 를 통해 컴퓨터에게 cs50 파일을 추가해야 한다고 명령합니다.

- 코드를 컴파일 할 때도 마찬가지로 clang -o string string.c -lcs50 명령을 통해 cs50 파일을 링크 시켜줘야 합니다. 

- 위 코드에서 " -l " 은 연결을 의미합니다. 따라서 위 명령어는 cs50파일을 연결해서 string.c 파일을 컴파일하라는 의미의 코드입니다.

- 또는 터미널 창에 명령어 프롬프트에 make string 을 입력하면 위와 같은 작업을 똑같이 수행합니다.

- make 라는 명령어는 알아서 어떤 인자를 사용해야 할지 파일명은 무엇으로 할지, 어떤 라이브러리나 코드를 연결했는지 등을 찾아서 알아서 만들어줍니다. 

- 따라서 지금부터는 프로그램을 컴파일 할 때 make를 입력하고 프로그램을 입력하면 됩니다. make string.c 이렇게 입력하지 말고 make string 이렇게만 입력해줘도 string.c 라는 소스코드를 컴파일 하라는 의미이구나를 압니다.

- make 라는 명령어는 cs50 한정적인 것이 아니라 유닉스와 리눅스를 사용하는 컴퓨터들에 포함되어 있는 일반적인 툴입니다.

 

 

 


3. C언어 - 조건문과 루프

학습 목표: 조건문과 루프를 c로 작성할 수 있습니다.

 

조건문

- C 는 지정하고자 하는 변수의 종류(데이터 타입)를 알려줘야 합니다.

- 숫자를 저장하고 싶을 때, 특히 정수(integer)를 저장하고 싶을 때 변수명 앞에 int 를 붙여줍니다.

 

 

- if ( ) 의 괄호 안에는 검사하고자 하는 조건이 들어가고, { } 안에는  조건을 만족할 때 수행하고자 하는 작업이 들어갑니다.

- == 는 일치 연산자 입니다. 등호 표시 하나는 이미 할당 연산자로 정해져 있기 때문에 =을 2개 사용하여 같다는 표현하자라고 오래전 약속되었습니다. 

- if, else, else if 뒤에는 세미콜론(;)을 붙이지 않습니다.

 

 

 

루프

- C 에서도 while 이나 for 을 통해서 루프를 구현

 

 

- while ( ) 괄호 안에 조건을 넣고 { } 안에 수행할 작업을 포함시킵니다.

- 위 코드에서는 true라는 항상 참이 되는 조건을 통해 while 루프가 영원히 수행됩니다.

 

 

- for 를 사용하면 for ( ) 안에 각각 (변수 초기화; 변수 조건; 변수 증가) 에 해당하는 코드를 넣어서 간단하게 표현할 수 있습니다.

 

 

실습

- 개발공부는 재미있다!"를 10번 출력하는 코드를 작성해보세요.

 

#include <stdio.h>

int main(void)
{
    for (int i = 0; i < 10; i++) {
        printf("개발공부는 재미있다!\n");
    }
}

 

 


4. C언어 - 자료형, 형식 지정자, 연산자

학습 목표:
1) 다양한 데이터 타입과 형식 지정자를 나타내는 방법을 학습합니다.

2) 다양한 연산자를 이용하여 조건문을 표현하는 방법을 학습합니다.

 

데이터 타입

- bool: 불리언 표현, (예) True, False, 1, 0, yes, no
-
char: 문자 하나 (예) 'a', 'Z', '?'

- string: 문자열

- int: 특정 크기 또는 특정 비트까지의 정수 (예) 5, 28, -3, 0

- long: 더 큰 크기의 정수

- float: 부동소수점을 갖는 실수 (예) 3.14, 0.0, -28.56

- double: 부동소수점을 포함한 더 큰 실수

* int 는 대략 40억 (four billion) 까지 셀 수 있습니다.

 

 

형식 지정자

- %c : char

- %f : float, double

- %i : int

- %li : long

- %s : string

 

 

기타 연산자 및 주석

- +:  더하기

- -: 빼기

- *: 곱하기

- /: 나누기

- %: 나머지

- &&: 그리고

- ||: 또는

- //: 주석

 

 

정수와 실수를 받아서 출력해보기

- 정수 데이터 타입을 표현할 때는 int, 정수의 형식 지정자는 %i

 

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

int main(void)
{
    int age = get_int("What's your age?\n");
    printf("You are at least %i days old\n", age * 365);
}

 

- 실수 데이터 타입을 표현할 때는 float, 실수의 형식 지정자는 %f

- 소수점 2번째 자리까지 나오게 하고 싶다면 형식지정자를 %.2f 로 작성하면 됩니다.

 

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

int main(void)
{
  float price = get_float("What's the price?\n");
  printf("Your total is %f.\n", price * 1.0625);
}

 

 


5. C언어 - 사용자 정의 함수, 중첩 루프

학습 목표: 사용자 정의 함수와 중첩 루프를 작성할 수 있습니다.

 

사용자 정의 함수

- 동일한 작업을 반복하는 코드를 사용자 정의 함수를 만들어 사용할 수 있습니다.

 

#include <stdio.h>

int main(void) {
  printf("cough\n");
  printf("cough\n");
  printf("cough\n");
}
#include <stdio.h>

void cough(void)
{
  printf("cough\n");
}

int main(void)
{
  for (int i = 0; i < 3; i++)
  {
    cough();
  }
}

 

- main 함수와 같이 중요한 함수는 바로 나오는 것이 좋습니다. 

- 그러나 위의 코드에서 cough와 main 함수의 위치를 바꾸면 main 함수 내에 있는 cough 를 인식하지 못해 오류가 발생합니다.

- 이런 오류를 방지하기 위해 void cough(void); 코드를 main 함수 위에 작성합니다. 이 코드는 cough 함수 전체를 알 수는 없지만 cough 라는 이름을 가진 함수가 있음을 알려줍니다.

 

#include <stdio.h>

void cough(void);

int main(void)
{
  for (int i = 0; i < 3; i++)
  {
    cough();
  }
}

void cough(void)
{
  printf("cough\n");
}

 

- 원하는 횟수만큼 "cough"를 출력할 수 있습니다.

 

#include <stdio.h>

void cough(int n);

int main(void)
{
  cough(3);
}

void cough(int n)
{
  for (int i = 0; i < n; i++)
  {
    printf("cough\n");
  }
}

 

cough 함수 내 int n 은, cough 함수가 입력값을 받는데 int 형식을 갖고 n 이라는 변수에 저장하겠다는 의미입니다.

 

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

int get_positive_int(void);

int main(void)
{
  int i = get_positive_int();
  printf("%i\n", i);
}

int get_positive_int(void)
{
  int n;
  do
  {
    n = get_int("Positive Integer: ");
  }
  while (n < 1);
  return n;
}

 

- get_positive_int 함수는 int 값을 반환합니다. 정의된 함수 왼쪽에 표시된 int는 함수의 반환 값의 종류를 의미합니다. 즉, 출력의 종류를 의미합니다.

- get_positive_int 함수 내에 정의된 void는 입력의 종류를 의미합니다. 입력값을 아무것도 받지 않는다면 void를 표시합니다.

 

 


6. C 언어 - 하드웨어의 한계

학습 목표: 메모리 용량이 프로그램의 구동에 미치는 영향을 설명할 수 있습니다. 

 

부동 소수점 부정확성

- 실수 x, y를 인자로 받아 x 나누기 y를 하는 프로그램이 있다고 가정했을 때,  x에 1을, y에 10을 입력하면 아래와 같은 결과가 나옵니다.

- 컴퓨터는 모든 정보를 0과 1로 저장하고 숫자 또한 마찬가지 입니다.

- 0.1 라는 실수를 0과 1로 구성된 이진수로 바꾸면 0.000110011... 무한 소수값이 나옵니다.

- 메모리는 유한한 값만 저장할 수 있기 때문에 무한 소수를 정확한 값으로 저장할 수 없습니다. 

- 약간의 오차가 있는 무한소수를 저장했기 때문에 아래와 같이 다소 부정확한 결과를 내게 되는 것입니다.

 

 

정수 오버플로우

- 비슷한 오류로 1부터 시작하여 계속해서 2를 곱하여 출력하는 프로그램이 있다고 가정했을 때, int 타입이 저장할 수 있는 수를 넘은 이후에는 아래와 같이 에러가 발생하며 0이 출력됩니다.

- int 는 32개의 비트(4byte) 의 크기만큼만 저장할 수 있습니다.

- 따라서, 다루고자 하는 데이터 값의 범위를 유의하며 프로그램을 작성하는 것이 중요합니다.

 

 


퀴즈

3. C언어로 작성된 hello.c 소스코드를 컴퓨터가 이해할 수 있는 머신코드로 컴파일 하기 위해 어떤 명령어를 프롬프트에 입력해야할까요?

$clang hello.c

 

4. 사용자 이름이 저장된 문자열 변수 name와 "Hello"를 연결해서 출력하려합니다. 올바른 C언어 코드는 무엇인가요?

printf("Hello, %s", name);

 

5. ‘x가 y와 같다면’ 이라는 조건문을 C 코드로 나타내면 어떻게 될까요?

if (x == y)

 

6. 변수 x가 입력되었을 때 x가 짝수인지 홀수인지 알아내는 프로그램을 구현하기 위해 사용하면 좋은 연산자는 다음 중 무엇인가요?

%

 

8. 아래와 같이 hello()라는 사용자 정의 함수를 작성한 후, 메인 함수에서 사용하려고 합니다. 파일 상단에 정의되어야하는 코드는 무엇일까요?

void hello(int n);

 

10. 컴퓨터 하드웨어의 한계로 인해 발생하는 문제 중 하나로, 변수가 담을 수 있는 최대 허용 범위를 벗어난 값을 저장해 예상치 못한 결과가 나오는 현상을 무엇이라고 하나요?

오버플로우

 

'CS50' 카테고리의 다른 글

5. 메모리  (0) 2023.08.24
4. 알고리즘  (0) 2023.08.22
3. 배열  (0) 2023.08.17
1. 컴퓨팅 사고  (0) 2022.12.13