2. C언어

양준식·2020년 7월 18일
0
post-thumbnail

1. C 기초


C로 “hello, world”를 출력하는 프로그램을 만들 수 있습니다.

C 언어

  • C는 아주 오래되고 전통적인 순수 텍스트 기반의 언어입니다.
  • sandbox.cs50.io 이라는 클라우드 기반의 프로그램을 사용하여 실습을 진행하였습니다. 아래의 코드를 살펴보도록 하겠습니다.
#include <stdio.h>

int main(void)
{
    printf("hello, world");
}
  • hello.c 파일을 생성하고 위의 코드를 작성합니다. (cf. .c : c 언어 파일 확장자)
  • prinf : print formatted

컴파일러(Compiler)

  • 컴파일러(Compiler): 우리가 직접 작성한 코드는 "소스 코드(Source Code)"라고 불립니다. 이를 2진수로 작성된 "머신 코드(Machine Code)"로 변환해야 컴퓨터가 이해할 수 있습니다. 이런 작업을 컴파일러(Compiler)라는 프로그램이 수행해줍니다.
  • Source Code(Input) >>> 컴파일러(Compiler) >>> Machine Code(Output)
  • Terminal에 명령어를 입력함으로써 컴파일 작업을 수행할 수 있습니다.
    cf. 마우스와 GUI(Graphical User Interface)로 할 수 있는 모든 것들을 명령어를 통해서 수행할 수 있습니다.

$ clang hello.c

  • $ : "Write something here". (Prompt, Shell)
  • clang : 코드를 컴파일하는 프로그램의 이름
  • 위의 명령어를 입력하는 순간 이진법의 Machine Code가 담긴 a.out이라는 파일이 생겼습니다.

$ ./a.out

  • 위의 명령어를 입력하여 a.out 파일을 실행합니다.
  • 파일을 실행하자 "hello, world"라는 결과가 출력되었습니다.

printf("hello, world\n");

  • 줄바꿈을 위해 \n 을 추가해 주었습니다.

2. 문자열


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

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

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

형식 지정자, 할당 연산자(대입 연산자)

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

  • string answer : C에서는 변수를 선언 시 어떤 데이터 타입인지 정확하게 명시해줘야 합니다.
  • 이 때 string형식지정자라고 부릅니다.
  • get_string 함수가 사용자의 이름을 반환하면 그 이름을 anwser라는 변수에 저장합니다.
  • 이렇게 오른쪽에 있는 것을 왼쪽에 지정할 때 할당 연산자(=)를 사용합니다.
  • 이제 컴퓨터의 메모리 어딘가에 사용자의 이름이 저장되어 있습니다.

라이브러리 사용

#include <cs50.h>

  • cs50.h 파일 안에 string이라는 문자열 형식과 get_string 이라는 함수에 대한 코드가 포함되어 있습니다. 이 파일을 포함해야 전체 코드를 컴파일 하고 실행할 수 있습니다.
  • 아래의 명령어를 입력하여 컴파일을 실행합니다.
  • $ clang -o string string.c -lcs50 (-lcs50 : link cs50)

make

  • 아래 make 명령어를 통해 간단하게 컴파일을 수행할 수도 있습니다.
  • $ make string
  • 위의 명령어를 입력 시 string.c 파일을 찾아 자동으로 컴파일 과정을 거친 string 파일을 생성해줍니다.
  • 아래와 같이 작성한 코드를 컴파일 하고 실행하면, 사용자에게 입력값을 받고 문장 내에 포함하여 출력하는 프로그램이 됩니다.


3. 조건문과 루프


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

init

init counter = 0;
  • counter라는 변수에 숫자를 저장해보겠습니다.
  • int 는 변수가 정수(integer)라는 것을 알려줍니다.
  • counter는 변수의 이름, 0은 그 값에 0을 저장(초기화)하는 것입니다.
  • 변수의 값을 1씩 증가하고 싶은 경우 아래와 같은 표현 방법들이 있습니다.
counter = counter + 1;

counter += 1;

counter++;

if (Conditional Statements)

if(x < y)
{
	printf("x is less than y.\n")
}
else if(x > y)
{
	printf("x is greater than y.\n")
}
else if(x == y)
{
	printf("x is equal to y.\n")
}
  • x == y : 일치 연산자(==)를 사용하여 두 개의 값이 같다는 것을 표현합니다.
  • 마지막 조건은 굳이 필요 없어 보이네요. 다음과 같이 수정해보겠습니다.
if(x < y)
{
	printf("x is less than y.\n")
}
else if(x > y)
{
	printf("x is greater than y.\n")
}
else
{
	printf("x is equal to y.\n")
}

while Loop

while (true)
{
	printf("hello, wolrd.\n");
}
  • "while somthing is true"
  • true라는 항상 참이 되는 조건을 통해 while 루프가 계속 실행되며, "hello, world"를 무한정 출력하게 될 것입니다.
  • 다음에는 반복문에 조건을 추가해보겠습니다.
int i = 0;
while (i < 50)
{
	printf("hello, wolrd.\n");
	i = i + 1;
}
  • i: integer
  • 위의 코드는 for문을 통해 더욱 간단하게 나타낼 수 있습니다.

for Loop

for(int i = 0; i < 50; i++)
{
	printf("hello, wolrd.\n");
}
  • for loop에는 아래와 같이 세 개의 input이 들어갑니다.
  • for(변수 초기화; 변수 조건; 변수 증가)

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


  • 다양한 데이터 타입과 형식 지정자를 나타내는 방법을 학습합니다.
  • 다양한 연산자를 이용하여 조건문을 표현하는 방법을 학습합니다.

c언어 데이터 타입

  • bool: 불리언 표현, (예) True, False, 1, 0, yes, no
  • char: 문자 하나 (예) 'a', 'Z', '?'
  • string: 문자열
  • int: 특정 크기(40억) 또는 특정 비트까지의 정수 (예) 5, 28, -3, 0
  • long: int 보다 더 큰 크기의 정수
  • float: 부동소수점을 갖는 실수 (예) 3.14, 0.0, -28.56
  • double: 부동소수점을 포함한 더 큰 실수

형식 지정자

printf 함수에서는 각 데이터 타입을 위한 형식 지정자를 사용할 수 있습니다. 여러가지 데이터 타입 마다 사용되는 형식 지정자를 알아보도록 하겠습니다. (ex. printf("hello, %s\n", answer); )

  • %c : char
  • %f : float, double
  • %i : int
  • %li : long
  • %s : string

기타 연산자 및 주석

  • + : 더하기, - : 빼기, * : 곱하기, / : 나누기, % : 나머지
  • && : 그리고, || : 또는
  • // : 주석

example) int

#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);
}

example) float

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

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

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


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

사용자 정의 함수(custom functions)

Q. 사용자 정의 함수를 사용하는 것의 장점은 무엇일까요?

// Example #1
#include <stdio.h>

void cough(int n); // first line of function code

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

void cough(int n)
{
    for (int i = 0; i < n; i++)
    {
        printf("cough\n");
    }
}
// Example #2
#include <cs50.h>
#include <stdio.h>

int get_positive_int(void);

int main(void)
{
    get_positive_int();
}

// 함수 왼쪽에 있는 단어는 출력을 의미하고(int)(type of its output)
// 괄호 안에 있는 단어는 입력을 의미(void > 인자가 필요 없는 경우)(type of its input)
// 입출력이 모두 없다면 void를 적어주면 됨
int get_positive_int(void)
{
    int n; // garbage value
    do
    {
        n = get_int("Positive Ingteger: ");
    }
    while(n < 1);
    return n;
}

중첩 루프

#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");
    }
}

6. 하드웨어의 한계


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

Memory

  • 컴퓨터는 우리가 작성한 프로그램을 구동하기 위해 다양한 물리적 장치를 사용합니다.
  • 그 중 하나는 메모리로, 프로그램이 필요한 정보가 저장되는 곳입니다.
  • 컴퓨터는 RAM(Random Access Memory)이라는 물리적 저장장치를 포함하고 있습니다.
  • 우리가 작성한 프로그램은 구동 중에 RAM에 저장되는데, RAM은 유한한 크기의 비트만 저장할 수 있기 때문에, 즉 메모리의 용량이 무한하지 않기 때문에 때때로 부정확한 결과를 내기도 합니다.
  • "fixed amount of memory in computer, which means there are fundamental limitations on what computers can do."

1) 부동 소수점 부정확성

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

int main(void)
{
    float x = get_float("x: ");
    float y = get_float("y: ");
    printf("x / y = %.50f\n", x / y);
}

  • 메모리의 공간이 유한하기 때문에 컴퓨터는 특정 지점에서 한계에 부딪힙니다.
  • float >>> 32비트의 메모리를 사용. 그 이상의 크기는 저장할 수 없습니다.
  • 결과적으로 계산할 수 있는 한도 내에서 0.1에 가장 가까운 값을 출력하게 됩니다.

2) 정수 오버플로우(Intiger Overflow)

#include <stdio.h>
#include <unistd.h>

int main(void)
{
    for (int i = 1; ; i *= 2) // 두 번째 input을 빈 칸으로 두었음. infinite loop
    {
        printf("%i\n", i);
        sleep(1);
    }
}

1999년에 큰 이슈가 되었던 Y2K 문제는 연도를 마지막 두 자리수로 저장했던 관습 때문에 새해가 오면 ‘99’에서 ‘00’으로 정수 오버플로우가 발생하고, 새해가 2000년이 아닌 1900년으로 인식된다는 문제였습니다. 그리고 세계는 수백만 달러를 투자해서 프로그래머들에게 더 많은 메모리를 활용해서 이를 해결하도록 하였습니다. 이는 통찰력 부족으로 발생한 아주 현실적이고 값비싼 문제였습니다.

또한 다른 사례로 비행기 보잉 787에서 구동 후 248일이 지나면 모든 전력을 잃는 문제가 있었습니다. 왜냐하면 강제로 안전 모드로 진입하였기 때문입니다. 이는 소프트웨어의 변수가 248일이 지난 뒤에 오버플로우가되어 발생하였기 때문이었습니다. 248일을 1/100초로 계산하면 대략 2의 32제곱이 나옵니다. 보잉을 설계할때 사용한 변수보다 너무 커졌던 것입니다. 이를 해결하기 위해 주기적으로 재가동을 하여 변수를 다시 0으로 리셋했습니다. 따라서 다루고자 하는 데이터 값의 범위를 유의하며 프로그램을 작성하는 것이 중요합니다.

profile
실력, 심력, 체력, 영력의 균형있는 성장을 추구합니다.

0개의 댓글