1) C언어
C언어에서 int main(void) 는 스크래치의 “초록색 깃발을 클릭했을 때” 블록과 같은 역할을 한다.
즉 '시작한다'의 의미를 가지고 있다고 보면 된다.
앞으로 작성할 코드는 모두 이 int main(void) { }의 중괄호 사이에 작성하게 될 것이다.
C에서는 스크래치에서의 say라는 함수는 없고 printf라는 함수가 있다.
printf(“hello, world\n”) 은 스크래치의 “‘hello, world’라고 말하기” 블록과 같은 역할을 한다.
글자나 단어, 문장을 적을 때는 언제나 텍스트에 " " 쌍따옴표로 감싸야 한다.
그리고 우리가 일상에서 문장의 끝에 마침표(.)를 붙이는 것 처럼 C에서는 세미콜론(;)을 붙여야 한다.
\n은 줄바꿈의 기능을 합니다. 키보드에서 ENTER의 기능과 동일하다.
#include <stdio.h>는 “stdio.h”라는 이름의 파일을 찾아서 “printf” 함수에 접근할 수 있도록 해준다.
우리가 Word로 문서를 저장했을때 "문서.docx"와 같이 .docx가 붙는 것 처럼,
C로 작성한 코드는 “파일이름.c”로 저장해야 한다. (확장자 “.c”는 C로 작성된 코드라는 의미이다.)
**컴파일러
우리가 직접 작성한 코드는 “소스 코드” 라고 불린다. 이를 2진수로 작성된 “머신 코드”로 변환해야 컴퓨터가 이해할 수 있다.
이런 작업을 컴파일러라는 프로그램이 수행해준다.
Source Code --- Compiler --- Machine Code
터미널창의 명령어 프롬프트에서 “$” 기호 옆에 원하는 명령어를 입력하면 된다.
clang hello.c 라는 명령어는 “clang” 이라는 컴파일러로 “hello.c”라는 코드를 컴파일하라는 의미이다.
그 결과 a.out 이라는 파일이 생성된다.
./a. out 이라는 명령어를 실행하면 컴퓨터가 현재 디렉토리에 있는 a.out이라는 프로그램을 실행하게 해준다.
(./a. out에서 제일 앞에 있는 .은 지금 있는 현재 폴더를 나타낸다.)
2) 문자열
C에서 스크래치의 ask함수와 가장 비슷한 것은 get_string 함수다.
String은 단어나 구절, 문장을 부르는 말이다. (숫자와는 다른 종류의 데이터)
사용자의 이름을 받아서 저장할 변수를 answer이라고 정해보자.
이때 변수는 xyz, name 등과 같이 자유롭게 정해도 된다.
하지만 여기서 유의해할 점은 C는 오래된 언어이기 때문에 변수가 저장하는 데이터의 종류를 아주 정확하게 명시해줘야한다.
그래서 우리는 저장하고자 하는 값의 종류가 문자열(string)이라는 것을 알려줘야 하는데 이때 string을 형식지정자라고 한다.
이름은 숫자가 아닌 문자이기 때문에 컴퓨터에게 "answer에 들어갈 것들은 문자야!"라고 말해주는 것이다.
우리가 일반적으로 사용하는 =은 같다 이다.
하지만 프로그래밍 언어에서는 오른쪽에서 왼쪽으로 가는 화살표와 비슷하다고 생각하면 편하다.
쉽게 말해 오른쪽에 있는 것을 왼쪽에 지정한다는 것이다. 이를 할당 연산자라고 한다.
get_string 함수가 사용자의 이름을 반환하면 그 이름을 anwser이라는 변수에 저장하는 것이다.
이제 컴퓨터의 메모리 어딘가에 사용자의 이름이 저장되어 있게된다.
이 것을 printf 함수로 출력을 해보자.
이때 유의할 점은 printf("hello, answer");이 아니라는 점!!
이 코드를 실행한다면 answer이 출력이 되어 hello, answer이 그대로 결과로 나온다.
우리는 answer이라는 변수에 들어있는 이름을 출력을 해야하기 때문에 %를 사용해 준다.
이 때도 어떤 종류의 인자를 받는지 말해줘야 한다.
우리는 이름이라는 문자열을 받기때문에 string에서의 s를 %뒤에 붙여서 인자를 받아줘야한다.
그래서 최종적으로는 printf("hello, %s\n", answer);이 되는 것이다.
가장 위에 포함된 cs50.h 파일 안에 string이라는 문자열 형식과 get_string 이라는 함수에 대한 코드가 포함되어 있다.
이 파일을 포함해야만 전체 코드를 컴파일 하고 실행할 수 있다.
터미널창에 아래 명령어를 입력하여 컴파일을 할 수 있다.
$ clang -o string string.c -lcs50
여기서 -o string 은 string.c 를 string.out 이라는 머신코드로 저장하도록 하는 명령어이다.
-lcs50은 “link”라는 의미를 지닌 -l 이라는 인자에 추가로 포함한 “cs50” 파일을 합친 것이다.
이를 통해 컴파일시 cs50 파일을 연결하도록 알려줄 수 있다.
약간은 복잡한 이런 과정 대신에, 아래 make 명령어를 통해 간단하게 컴파일을 수행할 수도 있다.
$make string
이와 같이 작성한 코드를 컴파일 하고 실행하면, 사용자에게 입력값을 받고 문장 내에 포함하여 출력하는 프로그램이 된다.
3) 조건문과 루프
C는 오래된 언어라 저장하고자 하는 변수의 종류를 꼭 알려줘야 한다.
counter라는 변수에 숫자를 저장하고 싶다면, 변수의 종류를 꼭 적어야한다.
여기서 int 는 변수가 정수(integer)라는 것을 알려주는 것이고, counter는 변수의 이름, 0은 그 값에 0을 저장(초기화)하는 것이다.
그리고 코드의 마지막에는 세미콜론(;)을 꼭 붙여야한다.
변수의 값을 1씩 증가시키는 것을 C에서는 어떻게 할까?
즉, counter에 1을 더한 값을 다시 counter에 저장(할당)한다는 의미가 된다.
더 간단하게 아래 두 가지 방식으로 수행할 수 있다.
마찬가지로 스크래치의 조건문 블록을 C코드로 나타내볼 수 있다.
if ( ) 의 괄호 안에는 검사하고자 하는 조건이 들어가고, { } 안에는 조건을 만족할 때 수행하고자 하는 작업이 들어간다.
여기에서는 조건이 True면 "x is less than y"를 출력을 하라는 것입니다.
else를 이용해 처음 조건이 아닌 경우에는 어떤 것을 하라라고 적어줄 수 있다.
이 경우에는 첫 번째 x < y 조건이 False, 즉 x가 y보다 작지 않을 경우에는 "x is not less than y"를 출력하라는 것이다.
else if 를 통해서 아래와 같이 조건을 추가할 수도 있다.
=는 할당 연산자이다. 이미 등호 표시 하나를 할당 연산자로 정했기에
=을 2개 사용하여 같다를 표현하자라고 정했고, 이를 일치 연산자라고 한다.
위의 코드에서는 if(x < y), else if (x > y), else if (x == y) 이렇게 3개의 조건문을 사용했다.
else if (x == y) 는 더 효율적으로 수정할 수 있다.
만약 x가 y보다 작지도 크지도 않다면 우리에게 남은 유일한 가능성은 x와 y가 같다는 것이기에
이를 수정하면 아래와 같다.
이렇듯 얼마나 효율적으로 코딩을 하는지, 혹은 얼마나 적은 메모리나 CPU를 사용해서 수행하는지는 매우 중요하다.
+보통 조건과 같은 것들의 끝에는 세미콜론을 붙이지 않습니다.
루프
스크래치에서의 루프는 “forever” 또는 “repeat 50”과 같은 블록을 통해서 수행했었다.
C에서도 while 이나 for 을 통해서 루프를 구현할 수 있다.
먼저 while 의 경우 아래 코드와 같이 while ( )의 괄호 안에 조건을 넣고 { } 안에 수행할 작업을 포함시키면 된다.
즉, C에서 루프를 구현하고 싶다면 성립 조건을 정해줘야 한다.
답이 네, 참, 혹은 1로 나올 수 있는 질문을 던져줘야 한다.
답이 참으로 나오게 하는 방법은 여러가지가 있을 수 있다.
5=5, 1<2 등등 하지만 가장 간단한 방법은 그냥 true를 적는 것이다.
아래 코드에서는 true라는 항상 참이 되는 조건을 통해 while 루프가 영원히 수행되도록 하자.
따라서 위의 코드는 계속해서 "hello, world"를 무한정 출력하게 될 것이다.
만약 특정 횟수만큼 작업을 수행하고 싶으면 어떻게 할까?
무언가를 셀 때 간단하게 정수를 나타내는 i를 사용합니다.
물론 변수명은 맘대로 적어도 상관 없다.
다시 while문으로 돌아가서 이번에는 i<50이라는 조건을 추가해준다.
처음에 i를 0이라고 정해주었고 while는 계속해서 i가 50보다 작은지를 물어볼 것이다.
따라서 이 코드가 정상적으로 작동하려면 i를 증가시켜야 한다. (i = i + 1, i += 1, i++ 모두 같은 결과를 나타낸다.)
진행 순서를 정리해보자면 아래와 같다.
i는 0으로 설정 -> i는 50보다 작은가? -> 작다 -> hello world를 출력한다 -> i를 1증가시킨다 -> i가 50보다 작은가?
-> (반복) -> i가 50보다 작은가? -> 작지 않다 -> 종료
따로 변수를 선언해도 되지만 아래와 같이 for 를 사용하면 for ( ) 안에
각각 (변수 초기화; 변수 조건; 변수 증가) 에 해당하는 코드를 넣어서 간단하게 표현할 수 있다.
가장 먼저 정수 값을 가지는 i라는 변수를 0으로 초기화하고, i가 50인지 매번 검사를 하고,
이를 만족하면 { } 안의 내용을 수행한 후에, i를 1씩 증가시킨다는 의미입니다.
while문과 비교하여 코드가 매우 간단해진 것을 확인할 수 있다.
4) 자료형, 형식 지정자, 연산자
데이터 타입
아래 목록은 변수의 데이터 타입으로 사용할 수 있는 것들이다.
- 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억까지 셀 수 있기 때문에 40억게 이상의 데이터를 가진 일부 거대 기업과 같은 상황이 아닌 일반 사용자들은 대부분 정수에 int를 사용한다.
형식 지정자
printf 함수에서는 각 데이터 타입을 위한 형식 지정자를 사용할 수 있다.
- %c : char
- %f : float, double
- %i : int
- %li : long
- %s : string
기타 연산자 및 주석
그 외에도 아래 목록과 같이 다양한 수학 연산자, 논리 연산자, 주석 등이 기호로 정의되어 있다.
- +: 더하기
- -: 빼기
- *: 곱하기
- /: 나누기
- %: 나머지
- &&: 그리고
- ||: 또는
- //: 주석
정수와 실수를 받아서 출력해보기
이번에는 문자열 대신 나이(정수)를 사용해보자.
# include <cs50.h>
# include <stdio.h>
int main(void)
{
int age = get_int("what's your age?\n");
int days = age * 365;
printf("Your are at least %i days old.\n", days);
}
get_int라는 정수 값을 받아오는 CS50 라이브러리에 있는 함수를 사용했다.
사용자의 나이는 오른쪽에서 왼쪽으로 복사되어 age라는 변수에 저장된다.
그 변수의 종류는 int 정수이다.
그럼 이 사람의 나이를 일 수로 환산하면 며칠인지 알아보자.
days라는 정수 변수에 age에 365를 곱한 수를 저장하고
printf 함수에 이번에는 문자가 아닌 정수이기 때문에 %i로 days의 인자를 받아주고 출력해준다.
이 코드를 좀 더 간단하게 작성하면,
# include <cs50.h>
# include <stdio.h>
int main(void)
{
int age = get_int("what's your age?\n");
printf("Your are at least %i days old.\n", age * 365);
}
이전에 days에 age에 365를 곱한 값을 저장했다.
days 대신 age*365를 넣으면 더 간편해진다.
더 줄여보면,
# include <cs50.h>
# include <stdio.h>
int main(void)
{
printf("Your are at least %i days old.\n", get_int("what's your age?\n") * 365);
}
age라는 변수를 없애버리고 age*365 대신에 get_int 함수를 넣어 365를 곱할 수 있다.
그렇다면 극단적으로 줄여버린 코드가 옳은 것일까?
마지막 코드는 좌우로 너무 길어서 가독성이 떨어진다.
디자인 측면에서는 시선이 왼쪽에서 오른쪽으로 가는 것보다 위에서 아래로 가는 것이 좋다.
읽기 편하고 이해하기 쉬운 코드가 더 선호되어지는 것은 팩트다.
이번에는 실수(float)를 사용해보자.
# 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);
}
get_float 함수를 사용하여 물건의 가격을 물어보고 가격을 받아 price에 저장해준다.
그런 다음 세금을 포함한 값을 계산해서 출력해보자. (메사추세츠의 부가세는 6.25%)
총액은 실수(float)이므로 %f를 사용해준다.
이제 코드를 실행해서 가격을 100으로 넣어보면,
결과 값으로 105.250000이 나온 것을 볼 수 있다.
하지만 소수점이 6번째 자리까지 나와 보기에 안 좋다.
이것을 소수점 두 번째 자리까지만 나오게 하려면,
printf("Your total is %.2f \n", price*1.0625);
%f에서 f앞에 '.원하는 자리수'를 넣어 %.2f로 소수점 2번째 자리까지 나오게 할 수 있다.
출력을 해보면 총 액을 좀 더 보기 좋게된 것을 볼 수 있다.
짝수인지 홀수인지 알려주는 코드짜기
#include <cs50.h>
#include <stdio.h>
int main(void)
{
int n = get_int("n: ");
if (n % 2 == 0)
{
printf("even\n");
}
else
{
printf("odd\n")
}
}
우선 get_int로 사용자들에게 정수인 숫자를 받아서 n에 저장한다.
간단하게 홀수 짝수를 구별할 수 있는 방법으로는 2로 나누어 나머지가 0이냐 1이냐를 보는 방법이 있다.
짝수면 나머지가 0이 될 것이고 홀수면 1이 될 것이다.
if ( n % 2 == 0 ) 을 풀어 쓰면 "n을 2로 나누었을 때 나머지가 0이면
printf("even\n"); -> even(짝수)을 출력하라" 이다.
홀수를 출력하는 것은 왜 else if (n % 2 == 1)으로 하지 않았냐고 묻는다면
왜냐하면 짝수 아니면 홀수 이기 때문에 else로도 충분하기 때문이다.
주석
C에서는 //로 주석을 달 수 있다.
// 주석입니다.
주석은 이 코드가 무슨 일을 하는지 설명한다.
그렇기 때문에 주석으로 잘 설명하는 습관은 자기 자신에게나 타인에게나 매우 중요하다.
'공부 STUDY > CS' 카테고리의 다른 글
CS50 | 알고리즘 - 검색 알고리즘, 알고리즘 표기법, 선형 검색 (0) | 2022.06.25 |
---|---|
CS50 | 배열 Array (2) - 배열, 문자열과 배열, 문자열의 활용, 명령행 인자 (0) | 2022.06.23 |
CS50 | 배열 Array (1) - 컴파일링, 디버깅, 코드의 디자인 (0) | 2022.06.23 |
CS50 | C 언어 - (2) (0) | 2022.06.21 |
1. 컴퓨팅 사고 Computational Thinking, Scratch (0) | 2022.06.19 |