* boostcourse 카테고리 내의 CS50관련 글은 네이버 부스트코스 [CS50 - 모두를 위한 컴퓨터 과학]을 수강 후 개인적으로 개념을 정리해본 글. 자세한 강의 내용을 확인하고 싶다면 네이버 커넥트재단이 운영하는 boostcourse 사이트에서 상시 무료 수강으로 진행되고 있는 CS50 강의 수강을 추천합니다.
모두를 위한 컴퓨터 과학 (CS50 2019)
부스트코스 무료 강의
www.boostcourse.org
“네이버 커넥트재단은 교육을 통해 개인의 지속적인 성장과 발전을 돕고, 원하는 곳 어디든 배움의 기회가 열리는 세상을 만들기 위해 노력합니다. 부스트코스는 커리어 역량을 강화할 수 있도록, 네이버 커넥트재단에서 기획하고 운영하는 실무형 온라인 교육 프로그램입니다.”
>> 부스트코스 홍보까지는 아니고 ㅎ 무료 강의 추천이다ㅎ
2021/01/10 - [boostcourse] - [부스트코스] CS50 코칭스터디 2기 오리엔테이션
2021/01/16 - [boostcourse] - [부스트코스] CS50 1강: 컴퓨팅 사고 강의 정리
CS50 2강 C언어
- C 기초
- 문자열
- 조건문과 루프
- 자료형, 형식 지정자, 연산자
- 사용자 정의 함수, 중첩 루프
- 하드웨어의 한계
2021/01/29 - [boostcourse] - [부스트코스] CS50 3강: 배열 강의 정리 (부제: 코칭스터디 3주차)
2021/02/05 - [boostcourse] - [부스트코스] CS50 4강: 알고리즘 강의 정리 (부제: 아직 2주나 혹은 벌써 2주 남은 코칭 스터디)
2021/02/12 - [boostcourse] - [부스트코스] CS50: 초보자는 헷갈리는 C언어 용어 정리
2021/02/14 - [boostcourse] - [부스트코스] CS50 5강: 메모리 강의 정리 (부제: 설연휴 만세)
2021/02/23 - [boostcourse] - [부스트코스] CS50 6강: 자료구조 강의 정리 (부제: CS50 수강 완료!)
2021/03/03 - [boostcourse] - [부스트코스] CS50 코칭스터디 2기 수료 후기
1. C 기초
C언어란,
벨 연구소에서 1971년에 리치(D.M.Ritchie)등에 의해 개발된 시스템 프로그래밍 언어이다. 프로그램을 간결하게 쓸 수 있고, 프로그래밍하기 쉬운 편리한 언어이다.
벨 연구소에서 1971년경부터 리치(D.M.Ritchie) 등에 의해서 설계 개발된 시스템 기술용의 프로그래밍 언어이다. UNIX 오퍼레이팅 시스템의 기술에 사용할 것을 목적으로 설계한 언어로 UNIX OS의 대부분이 이 언어로 개발되었다. 컴퓨터의 구조에 밀착한 기초 기술이 가능한 것과 간결한 표기가 될 수 있는 것 등을 특징으로 하고 있다. 시스템 기술(記術)용 언어의 경우에는 기억장치의 주소(어드레스) 등과 같은 하드웨어 자원까지 기술(記術)의 대상으로 할 것을 요구하고 있는데, C언어에서는 이러한 수준의 개념을 데이터 형이나 함수 등의 고수준 언어의 개념에 잘 대응하고 있다. 따라서 언어의 성격상 일반적인 범용의 언어와 거의 다를 바가 없다. 프로그램을 다른 종류의 컴퓨터에 이식하는 것도 용이하며, 범용 언어이기는 하지만 강력하고 고수준의 언어로 하는 것을 목표로 하고 있지 않다. C 언어는 프로그램 오류를 쉽게 발견하기 위한 기능은 부족하지만, 고수준 언어에서 자주 볼 수 있는 기술상의 제약이 적기 때문에 오히려 프로그래밍하기 쉬운 편리한 언어로 평가되며, 프로그램을 간결하게 쓰기 위하여 많은 연구를 한 언어이다. C 언어의 기본 특징은 ASCII코드 체계로 영문 소문자 집합을 바탕으로 하고 있으며, 함수(function)의 정의문들의 집합으로 구성되어 있고, 분할 컴파일을 할 수 있어 함수 정의부 밖의 외부 변수를 정의함으로써 컴파일 단위가 다른 함수의 외부 변수를 참조할 수 있게 되어 있다. 또한 프로그램의 함수 기능에는 FORTRAN의 SUBROUTINE 기능과 FUNCTION 기능을 가지고 있으며, 함수 호출시 매개변수의 값만 넘겨주는 호출 방식을 따르고 있고, 자료의 주소를 자유롭게 조작할 수 있는 점들이다.
[네이버 지식백과] C언어 [C language] (두산백과)
먼저, C언어를 사용하기 위해 CS50 Sandbox에 접속이 필요한데, Github 아이디가 있어야 로그인 할 수 있다. 남들이 가입한 것만 계속 봐와서 정체가 뭔지는 모르겠지만 C언어를 해보긴 해야겠으니 일단 가입.
CS50 Sandbox
Temporary programming environments for students and teachers.
sandbox.cs50.io
왼쪽의 Filetree, 오른쪽 상단의 코드 작성 부분, 오른쪽 하단의 터미널창 크게 3가지 화면으로 구성되어있다.
터미널 창에서 보이는 $
는 프롬프트(prompt)로, 컴퓨터가 입력을 받아들일 준비가 되었다는 것을 사용자에게 나타내어 주기 위해 컴퓨터 단말기 화면에 나타나는 신호다. 프로그램마다 각기 다른 프롬프트가 사용된다고 하는데, CS50 Sandbox에서는 $
표시다. 셸(shell)(명령어를 해석하는데 사용하는 프로그램. 사용자가 입력하는 명령어를 해석하고 수행하여 그 결과를 화면에 표시하여 준다.)이라고도 한다. $
옆의 두꺼운 흰색 네모는 커서다. PC통신이 생각나는 구조 ㅎㅎ
코드를 작성하기 위해 코드 작성 부분 상단의 +버튼을 눌러서 새로운 파일을 만들어준다. 이 때 제목 뒤에 꼭 .c
라는 확장자를 붙여줘야 한다. 한글 문서로 작성한 문서 프로그램에 .hwp라는 이름이 붙는 것처럼 .c
는 'C언어로 작성된 코드'라는 의미다. 문서 프로그램처럼 자동적으로 확장자를 붙여주지 않기 때문에 직접 작성해야 한다.
코드를 입력하는 곳에 위치한 커서 왼쪽에 보이는 숫자는 코드 작성의 편의를 돕기 위해 줄 번호를 표시해주는 것으로, 실제 코드에는 포함되지 않는다.
1.1 스크래치 vs C언어
블록을 옮겨 붙여 가며 그래픽 기반으로 코딩을 하는 스크래치와 달리 C언어는 순수 텍스트 기반의 언어다.
스크래치의 When 🏴clicked 블록과 의미와 비슷한 코드를 C언어로 작성한 모습. 시작한다는 의미를 가지고 있다. 앞으로 CS50강의를 통해 연습하게 될 모든 코드들은 이 중괄호의 안에 들어가게 된다고 한다.
C언어에서 스크래치의 say와 비슷한 함수로는 printf( )
가 있다. 논외로 얼핏 봤을 때 스크래치의 단어를 입력하는 흰 공간과 printf
뒤의 괄호 ( )에 단어를 입력하는게 구조가 비슷해 보인다.
이 짧은 코드에서도 C언의 기본적이지만 그래서 매우 중요한 내용 몇 개를 살펴볼 수 있다.
printf
는 문자열을 출력하는 함수(특정 기능을 수행하기 위한 문장들을 모아놓은 것)다.printf
라는 함수를 사용하기 위해선#include <stdio.h>
라는 코드를 작성해서 미리 작성된 함수에 접근할 수 있도록 해야 한다. (예시 1번 줄. <stdio.h> 관련 내용은 아래에)int main (void)
는 프로그램의 시작점을 정의한다. 중괄호 안의 내용이 어떤 것이든main
함수의 한 부분이 된다.- C언어에서 글자, 단어, 문장을 적을 때에는 명령어와 구분하기 위해 꼭 쌍따옴표 " "로 감싸줘야 한다. (예시 5번 줄)
- 문장이 끝날 때 점을 찍는 것처럼, 하나의 명령이 끝났을 때에는 세미콜론(;)을 붙여줘야 한다. (예시 5번줄)
-
\n
은 텍스트 줄바꿈 기능이다. (예시 5번 줄. 아래 사진 참고)
즉, \n
은 키보드의 Enter와 기능이 같다. 참고로, \백슬래시가 ₩원화로 보이는 경우가 있는데, 이 문제는 한글 윈도우 운영체제에서 생기는 문제로 다르게 표시되어도 기능은 같다.
1.2 소스코드와 머신코드
위에서 직접 작성한 코드는 "소스 코드(source code)"이고, 소스 코드(~.c)는 컴퓨터가 이해하지 못한다. 따라서 컴퓨터가 이해할 수 있도록 이진수로 작성된 "머신 코드(machine code)"로의 변환이 필요하다. 이런 변환 작업은 "컴파일러(compiler)"라는 프로그램이 수행해준다. 컴파일(compile)은 프로그램 제작자가 코볼ㆍ포트란 따위의 고급 언어로 쓰인 프로그램을 번역하고, 컴퓨터에서 실행할 수 있는 기계어 프로그램으로 고치는 과정을 의미하므로, 컴파일러는 해당 기능을 수행하는 프로그램을 뜻한다.
즉, 소스코드는 C, 파이썬, 자바, C++와 같은, 영어와 유사한 코드들이며 머신코드는 컴퓨터가 실제로 이해하는 0과 1의 조합이다. 소스코드의 번역을 수행하는 알고리즘 또는 소프트웨어가 컴파일러다. 참고로 머신코드는 "오브젝트 코드(object code)"라고도 한다.
C언어에서는 clang
이라는 프로그램을 통해서 코드를 컴파일할 수 있다. 터미널에 clang ~.c
를 입력후 엔터를 치면, 머신코드로 번역하여 같은 폴더 내에 a.out
이라는 이름의 파일을 생성한다.
a.out
의 아이콘을 보면 01101이라는 글자가 써져있음을 통해 이진수임을 알 수 있다.
만약, a.out
이라는 이름 외에 다른 이름을 사용하고 싶을 경우에는 clang -o 단어 파일명
을 입력하면 된다. -o
는 출력과 관련된 인자로 clang
관련 문서에서 확인할 수 있다.
clang -o
를 이용하여 머신코드를 생성할 경우에는 clang -o + 바꾸고자 하는 이름 + 현재 파일명 + -lcs50
까지 써줘야 한다. -lcs50
은 cs50을 링크시킨다는 의미로만 이해하고 넘어가면 된다.
실행 후 생성된 파일을 보면 아이콘이 a.out
과 다르게 보이지만, 실행에는 문제가 없다. .out
도 안붙길래 잘못된 건줄 알고 괜히 헤맸는데 실행 잘 됐다.
이 과정이 복잡하다면 make
명령어를 통해 소스코드와 같은 이름의 머신코드를 간단하게 생성할 수 있다.
make
는 명령어 뒤에 파일 이름만 입력하면 되므로, 간단하게 실행할 수 있다. 굳이 .c
를 붙이지 않아도 make
라는 프로그램이 알아서 .c
로 이해한 후에 머신코드로 변환한다.
이렇게 번역된 머신코드를 실행하고 싶다면 터미널 창에 ./머신코드 파일명
을 입력해주면 된다. 바로 위의 예시 상에선 ./a.out
또는 ./test-machinecode
, ./test
모두 같은 결과를 보여준다.
이 때 ./
에서 .
은 지금 현재 있는 폴더를 나타낸다. 풀어서 쓰자면, 현재 있는 폴더 중에서 a.out
파일을 실행시키라는 의미가 된다.
1.3 명령어 참고
아래는 강의에서 언급된 명령어들로 몇 개되진 않지만, 우선 정리해봤다.
명령어 | 뜻 | 수행 기능 |
ls | list | 현재 폴더나 디렉토리에 있는 파일의 리스트를 보여준다. (이때 파일 뒤에 *가 써져 있는 경우는 실행 가능하다는 의미이며 곧 컴퓨터가 이해할 수 있는 머신코드라는 뜻이 된다.) |
rm | remove | 파일 삭제 |
mkdir | make directory | 폴더 생성 |
rmdir | remove directory | 폴더 삭제 |
cd | change directory | 디렉토리 변경 |
1.4 주석
HTML의 <!-- -->
와 같은 기능을 수행하는 기능이 C언어에도 존재한다.
//
슬래시 두개 혹은 /*
와 */
사이에 글자를 입력하면 된다. /* */
는 티스토리 CSS 수정 시에도 볼 수 있다.
주석에 쓰여있는 글자들은 컴파일러에 의해 완전히 무시되기 때문에, 소스코드를 작성 중에 메모하는 용도로 사용하면 된다. 내가 쓴 코드도 나중에는 낯설게 느껴지기 때문에 주석으로 잘 설명하는 습관이 중요하다는 강의 노트가 있었다. 티스토리 HTML 편집할 때도 느낄 수 있는 주석의 중요성~!
2. 문자열(string)
스크래치에서 "What's your name?"이라고 질문한 뒤에, 사용자의 대답(이름)을 포함하여 다시 문장을 출력하는 구조는 위와 같이 만들 수 있다.
한편, C언어에서 스크래치의 ask 함수와 비슷한 함수는 get_string
함수다. 여기서 string
(문자열)은 문자 등을 1차원적으로 나열한 것을 의미하며, 단어, 구절, 문장 등을 숫자 데이터 등과 구분하여 가리키기 위해 사용된다. 아래 예시에서 사용된 get_string
이라는 함수는 <cs50.h>
에 포함된 함수 코드이므로 <cs50.h>
를 꼭 포함해야 한다(소스 코드 상단에 #include <cs50.h>
를 입력하면 된다).
C언어 라이브러리에 관한 설명은 아래의 더보기 클릭.
참고1: C표준 라이브러리 (<stdio.h>에 관한 설명도 볼 수 있다.)
C 표준 라이브러리 - 위키백과, 우리 모두의 백과사전
위키백과, 우리 모두의 백과사전. C 표준 라이브러리(C standard library)는 C 언어를 위한 표준 라이브러리로서, ANSI C 표준에 의해 명시되었다.[1] 이것은 상위 집합인 C POSIX 라이브러리와 동시에 개
ko.wikipedia.org
참고2: CS50 라이브러리 문서
CS50 Library for C
Installation: Ubuntu:$ curl -s https://packagecloud.io/install/repositories/cs50/repo/script.deb.sh | sudo bash $ sudo apt install libcs50 Fedora:$ curl -s https://packagecloud.io/install/repositor...
cs50.readthedocs.io
- 포스트 상단의 1. C언어에서 나왔던
make
라는 명령어는 일반적인 프로그램으로, 유닉스와 리눅스를 사용하는 모든 컴퓨터들에 포함되어 있는 일반적인 툴이라고 한다. - CS50 Sandbox는 그 자체로 클라우드 상의 컴퓨터다. CS50 샌드박스에 로그인하면 리눅스라는 운영체제로 돌아가는 클라우드 서버의 접근 권한을 갖게 되는데,
clang
,make
,ls
,rm
와 같은 명령어들은 모두 이 운영체제(리눅스) 안에 있다. 따라서make
라는 명령어를#include <stdio.h>
코드 안에서 쓸 수 있을 뿐만 아니라#include <cs50.h>
안에서도 각각 사용할 수 있는 것이다.make
명령어는 윈도우와 맥에도 포함된 명령어이지만, 이름을 입력해서 실행하는 프로그램으로 아이콘을 더블 클릭(윈도우와 맥의 방식)하는 프로그램은 아니다. <cs50.h>
는 CS50 수업을 위해 만들어진 라이브러리(여러 함수들을 모아둔 것)로, CS50 수업에서 학생들이 좀 더 쉽게 코딩을 짤 수 있게 CS50 라이브러리 안에 여러 함수(get_int, get_double, get_float 등등으로 아래에 다시 나온다)를 만들어 둔 것이다.<stdio.h>
는 표준 라이브러리로, 가장 많이 쓰고 가장 보편적으로 사용하는 라이브러리다. 이 외에도 표준 라이브러리에는<math.h>
,<time.h>
등이 있어서 자신이 코딩하는데 필요한 함수들을 그때 그때 라이브러리를 불러와서 다른 사람들이 만들어둔 함수를 사용할 수 있다.- 따라서
<cs50.h>
는 sandbox.cs50.io가 아닌 Visual Studio 같은 곳에서 CS50 라이브러리를 사용할 수 없다. 표준 라이브러리는 기본적으로 설치가 되어 있기 때문에 사용이 가능하지만 앞서 CS50 라이브러리는 수업을 위해 만들어진 라이브러리이므로, sandbox.cs50.io처럼 미리 설치가 된 곳이 아니면 따로 설치를 해야만 사용이 가능하다. <~.h>
는 헤더파일을 의미한다.
스크래치의 ask What's your name?과 get_string("What's your name?\n");
은 비슷한 기능을 수행한다. 그런데 C언어의 경우 사용자에게 받은 답변을 변수로 저장해주는 명령도 해줘야 하기 때문에 왼편에 string answer =
를 덧붙여야 한다. 변수에 대한 네이밍은 answer
뿐만이 아니라 xyz
, name
등 원하는 어떤 단어로도 대체 가능하지만, string은
해당 답변이 문자열 데이터임을 뜻하는 형식지정자이기 때문에 꼭 붙여줘야만 한다. 즉, 사용자가 입력한 데이터의 종류에 대해 컴퓨터에게 알려주는 역할을 하는 것이다.
또 string answer
뒤의 =
은, '같다'의 의미가 아니다. 프로그래밍 언어에서 =
은 오른쪽에 있는 함수를 왼쪽에 지정한다는 의미로, 할당 연산자라고 한다. 위의 식을 예시로 풀이하자면, get_string
의 함수에 대한 값을 string
데이터 값을 가진 answer
라는 변수에 저장한다는 것이다.
질문에 대한 답변을 변수로 저장 후에 바로 대답을 출력하기 위해선 printf
함수를 이용하면 된다.
답변을 출력하는 문장을 입력할 때에는 사용자가 입력한 변수가 그대로 출력될 수 있도록 해줘야 하기 때문에 "hello, answer."라고 바로 작성하는 것이 아니라, %
를 이용하여 사용자가 입력한 변수를 출력하고 s(string)
를 붙여 해당 값이 문자열 종류의 인자임을 알려줘야 한다. 줄바꿈 명령어 입력 후 쌍따옴표를 이용해 문장을 마무리한 뒤에 , answer(변수 이름)
를 입력하여 명령을 마무리한다.
printf
가 작동하는 방식은 쌍따옴표 사이에 들어간 하나의 문자열을 입력으로 받는다고 한다. 이 문자열 안에 형식 지정자가 있다면, 쉼표와 변수명(예시의 경우 answer)를 같이 입력해 줌으로써 컴퓨터에게 가져와야 할 값을 정확하게 알려줘야 한다. 만약, 위의 printf
코드 내에서 변수를 하나 더 추가하게 된다면, 코드는 길어지겠지만 쉼표와 변수명을 다시 추가해주기만 하면 된다. 변수들을 위한 형식 지정자를 문자열 내에 하나씩 넣어주면 왼쪽에서 오른쪽 순으로 지정이 된다. printf("hello, %s %s.")
와 같이 변수가 나란히 있을 경우 쌍따옴표 뒤에 ,(앞 변수 이름)
입력 후 ,(새로운 변수 이름)
을 입력하면 되는 것이다. ,(앞 변수 이름)
은 두 개의 %s
중 전자, ,(새로운 변수 이름)
은 후자에 해당하는 것이다.
3. 조건문과 루프
3.1 형식 지정자
스크래치에서는 변수(여기에선 counter; 이름은 다르게 써도 상관없다.)를 생성하고 0을 저장하기 위해 위와 같은 블록을 사용한다.
C언어에서는 숫자를 사용하기 위해 int
라는 형식 지정자가 필요하다. 위쪽의 예시처럼 counter
(변수 이름. 다르게 써도 상관 없다.)라는 변수가 숫자임을 알려주기 위해 왼쪽에 int
라고 입력해줘야 하는데, 이 때 int
는 integer
의 약자로 정수를 의미한다. 즉 포스트 내 2. 문자열에서 봤던 string answer =
코드와 의미는 다르지만 같은 구조를 취한다. 다시 int counter = 0 ;
이라는 코드로 돌아가서, 이 코드는 정수 counter
변수에 0
을 저장(초기화)한다는 의미를 뜻한다.
변수의 값을 증가시키는 식은 위와 같다.
C언어의 코드에서 다시 한 번 유의해야 할 부분은 =
은 같다는 의미가 아니라, 오른쪽을 왼쪽에 할당한다는 의미이다. 즉, 위의 예시 코드는 변수의 값(counter)에 1을 더해 다시 counter
라는 변수에 할당한다는 뜻이 된다.
다소 긴 처음의 코드 대신 아래 두 개의 코드를 사용할 수도 있다.
3.2 if조건문
printf
의 함수 마지막에는 세미콜론이 붙었지만, 조건문인 if
뒤에는 세미콜론을 붙이지 않는다.
여기에서 조건을 하나 더 추가하게 될 경우에는 각각 아래와 같다.
보다 자세하게 나누기 위해, '작지 않다'를 다시 '크다'와 '같다'로 나눈다.
이 때 C언어에서 사용된 'x는 y와 같다'에 대한 코드는 ==
이다. =
는 C언어에서 이미 할당 연산자로 기능하기 때문에 '같다'의 의미를 가질 수 없다. 따라서 할당 연산자 두 개를 이어붙여 같다는 의미로 사용한다. ==
는 일치 연산자라고 한다.
그리고 이 식에서, x=y
이다는 조건문은 굳이 필요하지 않은 부분이다. 왜냐하면 x
가 y
보다 크거나 작지 않다면, 같은 값이라는 의미가 되기 때문이다. 따라서 식을 보다 간결하게 수정해 볼 수 있다.
3개의 조건문을 모두 사용했을 때 보다 조금 더 간결해졌다. 예시에서는 차이가 두드러지지 않지만, 코딩에서는 같은 코드를 어떻게 효율적으로 구성하느냐가 매우 중요하다. 효율적인 코딩은 결국 더 적은 메모리와 CPU를 사용해서 같은 기능을 수행한다는 의미가 되기 때문이다.
3.3 루프(반복 순환) while, for
스크래치에서는 forever 또는 repeat을 통해 계속 또는 정한 만큼 반복할 수 있도록 할 수 있고, C언어에서는 while
또는 for
을 통해서 루프를 구현할 수 있다.
먼저 C언어의 while
의 경우 오른쪽 옆의 괄호 ( )
안에 조건을 넣고 수행할 작업을 아래 포함시키면 된다. 즉, 루프를 성립시키기 위해서는 조건이 필요하다. 이 때 조건에 대한 답이 네(yes), 참(true), 1(2진수)이 될 수 있도록 해야 하는데, 여러가지 방법이 있을 수 있겠지만 가장 간단한 방법은 그냥 true
라고 적는 것이다. 따라서 위의 코드처럼 작성할 경우 계속해서 "DATA"라는 값을 출력한다.
만약 특정한 값만큼만 출력하고 싶다면, 조건을 추가해주면 된다.
보통 프로그래머들은 무언가를 셀 때 간단하게 정수라는 의미를 나타내기 위해 i
를 자주 쓴다고 하니, 긴 변수 이름 대신 간단하게 i
라고 작성했다. 물론 이는 보통의 경우일 뿐 원한다면 다른 이름으로 작성해도 상관없다.
작성된 소스 코드를 해석해보자면, 먼저 i=0
이라고 정해진 상태다. 그 다음으로 while (i<10)
, i
가 10보다 작다면 이라는 조건이 붙었다. 이 경우 while
은 계속해서 i
가 10보다 작은지를 물어본다. 따라서 이 코드를 정상적으로 작동시키려면 i
를 증가시켜야 한다. 그래서 마지막에 i = i + 1;
이라는 코드가 추가되었다. i = i+1;
은 i += 1;
, i++;
로 대치될 수 있다.
소스 코드가 진행되는 방식을 풀이하자면, 아래와 같다. (숫자 리스트가 원하는 대로 표기가 안돼서 일단 점 리스트로 표기함)
- i는 0에서 시작한다.
- i가 10보다 작다면,
- "DATA MAP\n"을 출력한다.
- i를 1 증가시킨다.
- 2번으로 돌아간다. (반복)
- 만약 i가 10보다 작지 않다면,
- 종료한다.
이렇게 while
을 이용하여 따로 변수를 선언해도 되지만, 아래와 같이 for
을 사용하면 for ( )
안에 각각 (변수 초기화; 변수 조건; 변수 증가)
에 해당하는 코드를 넣어서 간단하게 표현할 수도 있다.
for
뒤의 괄호 안은, 가장 먼저 정수 값을 가지는 i
라는 변수를 0
으로 초기화하고, i
가 10
인지 매번 검사를 해서 이를 만족하면 { }
안의 내용을 수행한 후에, i
를 1
씩 증가시킨다는 뜻이다. while
코드와 비교했을 때 for
로 작성한 코드가 훨씬 간단해졌다.
4. 자료형(데이터 타입), 형식 지정자, 연산자
4.1 표, 리스트 정리
4.1.1 데이터 타입 정리
bool | 불리언 표현 | ex. True, False, 1, 0, yes, no |
char | 문자 하나 | ex. 'a', 'B', 'y', 'n', '?' |
string | 문자열 | 쌍따옴표 안에 들어간 한 개 이상의 문자들. 보통 char 하나하나 보다 크다. |
int | 특정 크기 또는 비트까지의 정수 | ex. 3, 65, -9, 0 / 40억까지 셀 수 있다. |
long | 더 큰 크기의 정수 | 더 많은 비트를 사용하여 int보다 더 높은 수를 센다. * 40억개 이상의 데이터를 가진 일부 거대 기업(페이스북, MS)과 같은 상황이 아닌 일반 사용자들은 대부분 정수에 int를 사용한다. |
float | 부동 소수점을 갖는 실수 | ex. 3.14, 0.0, -65.56 |
double | 부동 소수점을 포함한 더 큰 실수 |
4.1.2 CS50 라이브러리 내의 get 함수
- get_string
- get_char
- get_double
- get_float
- get_int
- get_long
대충 이런게 있네~하고 넘어가면 됨.
4.1.3 형식 지정자
%c
: char%f
: float, double%i
: int%li
: long%s
: string
4.1.4 기타 연산자 및 주석
+
: 더하기-
: 빼기*
: 곱하기/
: 나누기%
: 나머지&&
: 그리고||
: 또는//
: 주석/* */
: 주석
4.2 정수와 실수
4.2.1 정수와 실수를 받아서 출력하기 - 정수(int)
사용자의 나이(정수)를 묻고, 나이에 365를 곱해 몇 일이 지났는지 환산하는 식을 출력하는 식은 아래와 같다.
(get_int는 CS50 라이브러리에 있는 함수이므로 <cs50.h>를 포함해주는 것을 잊지 말아야 한다.)
포스트 내 2. 문자열에서 문자열을 출력할 때와 크게 다르지 않은 구조임을 볼 수 있다. 다만 변수의 값이 정수로 바뀌었고, 변수에 곱셈을 하는 명령이 추가되었다. 변수가 정수이기 때문에 %
뒤의 형식 지정자도 i
가 되었다.
위의 코드에서 days
라는 조건을 추가하는 대신 바로 age
에 365를 곱해서 보다 간단하게 수정했다.
2번 사진 속의 코드에서 또 다시 줄여보면 이렇게 표현해 볼 수 있다. 그러나 이 코드는 가로로 너무 길기 때문에 가독성이 다소 떨어진다. 코드 디자인 측면에서는 시선이 왼쪽에서 오른쪽으로 가는 것보다 위에서 아래로 가는 것이 더 좋다고 한다. 물론 정답이 있는 문제가 아니고 선호의 문제이기 때문에 편한 방법을 이용하면 되지만, 보통 이해하기 쉽고 읽기 편한 코드가 선호된다.
4.2.2 정수와 실수를 받아서 출력하기 - 실수(float)
물건의 가격을 물어보고, 해당 가격에 세금을 포함한 값을 계산하는 식을 만들어보면 아래와 같다.
(강의 촬영 당시 메사추세츠 부가세를 참고한 식)
위의 소스 코드를 컴파일 한 후 실행하면 위와 같은 결과물이 나온다. 소수점 6번째까지 나오는데 너무 길기 때문에 두자리 수까지 나오게 줄이고 싶다면, 소스 코드에서 %.2f
라고 입력해주면 된다.
다른 코드에서도 %f
앞에 .원하는 소수점 자리 숫자
를 입력하면 된다.
4.3 짝수인지 홀수인지 알려주는 코드 작성해보기
get_int
로 사용자에게 정수를 받아서 n
이라는 변수에 저장한다고 했을 때, 받은 정수를 짝/홀로 나누는 방법으로는 먼저 정수 하나하나 일일히 해당 값을 지정하는 방법이 있을 것이다. 그러나 정수를 대상으로 하면, 그 값은 무한대이므로 사실상 불가능한 코드다. 따라서 가능한 방법으로는 정수를 2로 나누었을 때 나머지값이 0인지, 혹은 1인지를 판단한 뒤에 짝/홀임을 출력해주는 방법이 있다.
4.4 동의 여부를 묻는 코드 작성해보기
대뜸 동의하냐고 묻는 당황스러운 코드인데, 중요한 부분에 대한 설명이 있어서 넣었다. 먼저 해당 코드를 실행한 화면(오른쪽 사진)을 보면, 동의하냐는 질문에 N 또는 n으로 대답해도 모두 동의하지 않았다는 대답을 한다. 즉, 대문자와 소문자 모두 'Disagreed'에 유효한 값으로 작용했다.
이렇게 두 가지 답 모두 유효할 수 있는 이유는 조건문에서 변수의 값에 '또는'을 뜻하는 ||
연산자를 추가했기 때문이다.
참고로 동의하냐는 질문에 엉뚱한 대답을 할 경우에는 아무런 일도 일어나지 않는다. 소스 코드에서 루프(반복)가 없기 때문에 다시 질문을 하지 않고 해당 코드는 종료된다. 만약, 루프가 있는데 예상에서 벗어난 질문을 할 경우 제대로 된 답을 할 때까지 계속 묻는다ㅋㅋㅋ
5. 사용자 정의 함수, 중첩 루프
5.1 사용자 정의 함수
5.1.1 사용자 정의 함수 만들기
가령 기침을 세번 하는 코드를 작성한다고 할 때, 가장 쉬운 방법은 printf
함수를 원하는 수만큼 붙여넣어 기침을 하도록 하는 것이다. 그러나 동일한 작업을 반복하는 것이므로 아래와 같이 간단하게 구성해볼 수 있다.
참고로 숫자의 기본 설정값을 0이 아니라 1로 설정하고싶다면, (int i=1; i<4, i++)
또는 (int i=1; i<=3, i++)
로 작성해도 코드는 문제없이 실행된다.
이렇게 만든 코드를 함수로 만들고 싶다면 아래의 코드대로 작성해주면 된다.
void 함수이름 (void)
입력 후 아래에 명령을 입력한다. 그리고 main
코드 안에 조건을 입력 후 함수 이름을 적어주면 된다.
그러나 코드를 작성할 때에는 메인코드가 위에 바로 보일 수 있도록 구성하는 것이 중요한데, 이 방법은 함수의 코드가 길 경우에는 main
코드가 너무 아래에 위치하게 된다는 단점이 있다. 단순하게 생각해서 메인 코드를 위로 올리고 함수의 코드를 아래로 작성해버리면, 컴퓨터는 순서대로 코드를 읽어내리기 때문에 오류가 발생한다.
따라서 상단에 만들고자 하는 함수의 코드 첫번째 줄(함수 프로토 타입이라고도 한다)을 복사 붙여넣기 후 세미콜론만 덧붙여 준다음 상세한 코드는 메인 코드 아래에 작성해주는 방식으로 구성하면 된다. 예시로 작성한 코드는 코드 자체가 간단해서 큰 변화가 없는데, 코드가 길고 복잡하다면 훨씬 효율적인 구성이 될 수 있다.
메인코드에서 직접 실행 조건을 설정하기 보다는 아예 함수에 실행 조건이 포함되어 있게 구성을 하고 싶다면 위와 같은 방법으로 구성하면 된다. 변형한 코드에서는 함수 자체에 for
조건이 포함되어 있으므로 메인 코드에서는 for
조건을 입력할 필요없이 실행하고 싶은 횟수만 입력해주면 된다.
기존의 void cough (void)
에서 void cough (int n)
으로 바뀐 것을 통해 (void)
는 특별한 입력 값이 없을 때에 사용되는 것을 알 수 있으나, 자세한 설명은 이후의 강의에서 나온다.
5.1.2 사용자 정의 함수 사용하기
역시 메인 코드 상단에 함수 프로토 타입을 적고 메인 코드 아래에 get_postive_int
라는 함수가 정의되어 있다. 그러나 5.1.1의 예시와 다른 점이 몇 개 있다.
void 함수이름 (void)
가 아니라int 함수이름 (void)
인데, 이 함수는 이 전에 사용했던get_int
나get_string
함수처럼 어떤 값을 받아와서 변수에 저장하는 것처럼 이 함수가 뭔가를 반환하게 하기 위해서 출력의 종류(int: 정수)를 지정했기 때문이다.- 메인 코드에서 적은 함수 이름 뒤의 괄호 안에는 아무것도 넣지 않았다. 이 함수에서는 아무 양의 정수나 받으면 되기 때문이다.
- 함수의 코드를 살펴보면 상단에
int n;
이 위치한다. 컴퓨터에게int
형식의n
이라는 변수를 받아달라는 일종의 힌트로, 어떤 값을 저장할지 아직 모르기 때문에 그냥int n;
만 적은 것이다. 따라서 이n
은 나중에서야n
의 값이 나오게 되기 때문에 쓰레기 값(Garbage Value)라고 한다.
✔️함수의 이름 왼쪽에는 출력의 종류 / 오른쪽에는 입력의 종류이다. 즉, 출력의 종류 + 함수 이름 + (입력의 종류)
다.
5.2 중첩 루프
#include <cs50.h>
#include <stdio.h>
int main(void)
{
int n;
do
{
n=get_int("Size:");
}
while (n<1);
for (int i=0; i<n; i++)
{
for(int j=0;j<n;j++)
{
printf("#");
}
printf("\n");
}
}
강의에서 일단 코드를 보여주고 중첩 루프의 개념을 설명하는 방식으로 진행되서 일단 코드부터 따라 써봤다.
코드를 설명하자면, 우선 do{ } while()
을 사용하면 조건과 상관없이 최소한 한 번은 { }
안의 내용을 실행할 수 있다고 한다. 또한 while
조건 때문에 n
이 음수일 경우엔 계속 반복해서 사이즈를 묻는다.
n
이 양수일 경우에만 for
루프를 두 번 중첩해서 돌면서 #
을 출력하는데, 첫 번째 루프에서는 변수 i
를 기준으로 n
번 반복하고, 그 안의 내부 루프에서는 변수 j
를 기준으로 n
번 반복한다. 내부 루프에서는 #
을 출력하고, 내부 루프가 끝날 때마다 줄바꿈을 수행해서 최종적으로는 가로가 n
개, 세로가 n
개인 #
이 출력된다.
6. 하드웨어의 한계
컴퓨터에는 RAM(랜덤 액세스 메모리)이라는 물리적 저장장치가 있다. 사용자가 작성한 프로그램은 구동 중에 RAM에 저장되는데, RAM은 유한한 크기의 비트만 저장할 수 있기 때문에 때때로 부정확한 결과를 내기도 한다.
⚠️즉, 저장 가능한 공간이 유한하므로, 컴퓨터가 저장할 수 있는 숫자 역시 유한하다. 따라서 컴퓨터가 할 수 있는 일에는 근본적인 한계가 있다.
6.1 부동소수점 부정확성
정확한 결과는 0.1이 되어야 하지만 float
에서 저장 가능한 비트 수가 유한하기 때문에 부정확한 결과값이 나오게 된다.
6.2 정수 오버플로우(overflow)
1부터 시작해서 1초 후에 2씩 곱하는 코드를 작성 후 실행해보면, int
가 저장할 수 있는 수를 뛰어넘었을 때 오류가 나면서 계속해서 0을 출력한다. int
는 32개의 비트를 사용하기 때문에 10억을 넘기게 되면 앞으로 넘어갈 수 있는 1이 사라지게 되면서 생긴 문제이다.
6.2.1 실제 오버플로우의 예
- Y2K, 일명 밀레니엄 버그 사건.
2000년대 이전에 컴퓨터에서 년도를 표기할 때는 저장공간을 절약하기 위해 끝의 두자릿수만 사용하여 표현했다. 그러다 보니 다가오는 2000년이 (19)00이 되어버리는 문제가 발생했다. 이는 곧 수 많은 시스템에서 오류가 날 수 있음을 뜻했기 때문에 전 세계에서 수백만 달러를 들여서 문제를 해결해야만 했다. - 보잉787 드림라이너 여객기의 세이프 모드
보잉787의 여객기는 구동 후 248일이 지나면 강제로 안전 모드에 진입하는 문제가 있었다. 248일을 1/100초로 계산하면 대략 2의 32승이 나오는데(왜이렇게 계산하는 건지는 모름), 보잉이 실제 787비행기에서 중요한 부분을 설계할 때 사용한 변수가 너무 커져서 전원이 켜진 뒤 248일이 지나면 오버플로우가 발생하고 결국 비행기 내의 모든 전력이 끊기게 되는 것이다. 결국 이를 해결하기 위해 소프트웨어를 업데이트 하는 한편 248일 마다 비행기를 재시동했다고 한다.
정리글은 어떻게 마무리해야 될지 모르겠어서
기초도 힘든 코딩 찌질이의 참담한 심정을 담아낸 짤로 마무리.
'STUDY > boostcourse' 카테고리의 다른 글
[부스트코스] CS50: 초보자는 헷갈리는 C언어 용어 정리 (0) | 2021.02.12 |
---|---|
[부스트코스] CS50 4강: 알고리즘 강의 정리 (부제: 아직 2주나 혹은 벌써 2주 남은 코칭 스터디) (0) | 2021.02.05 |
[부스트코스] CS50 3강: 배열 강의 정리 (부제: 코칭스터디 3주차) (0) | 2021.01.29 |
[부스트코스] CS50 1강: 컴퓨팅 사고 강의 정리 (0) | 2021.01.16 |
[부스트코스] CS50 코칭스터디 2기 오리엔테이션 (0) | 2021.01.10 |