C언어

Life is ninanino·2022년 8월 24일
0
  • stdio.h
  • clang
  • 컴파일러
#include <stdio.h>

int main(void)
{
    printf("hello,wolrd\n");
}

int main(void)는 '시작한다'의 의미를 가지고 있다.
코드는 중괄호 사이에 작성한다
글자나 단어, 문장을 적을 때는 텍스트에 "" 쌍따옴표로 감싸야 한다
C는 문장의 끝에 세미콜론(;)을 붙인다
\n은 줄바꿈의 기능을 한다
#include <stdio.h>는 "stdio.h"라는 이름의 파일을 찾아서 "printf" 함수에 접근 할 수 있도록 한다

컴파일러

우리가 직접 작성한 코드는 "소스 코드"라고 불린다
2진수로 작성된 "머신 코드"로 변환해야 컴퓨터가 이해할 수 있따
이런 작업을 컴파일러라는 프로그램이 수행해준다

터미널 창의 명령어 프롬프트에서"$" 기호 옆에 우리가 원하는 명령어를 입력하면 된다
clang hello.c 라는 명령어는 "clang" 이라는 컴파일러로 "hello.c"라는 코드를 컴파일 하라는 의미이다

그 결과 a.out이라는 파일이 생성된다.

./a.out 이라는 명령어를 실행하면 컴퓨터가 현재 디렉토리에 있는 a.out이라는 프로그램을 실행하게 한다.
(./a.out에서 제일 앞에 있는 .은 지금 있는 현재폴더를 나타낸다.)

  • 형식지정자
  • string
  • make

CS50 sandbox에서는 스크래치의 ask 함수와 가장 비슷한 것은 get_string함수이다
String은 단어나 구절, 문장을 부르는 말이다(숫자와는 다른 종류의 데이터)


사용자의 이름을 받아서 저장할 변수를 스크래치와 같이 answer이라고 정했다.
변수는 xyz,name등과 같이 마음대로 정할 수 있다.
C는 변수가 저장하는 데이터의 종류를 정확하게 명시해줘야 한다
저장하는 값의 종류가 문자열(string)이라는 것을 알려줘야하는데, 이때 string을 형식지정자라고 한다

우리가 일반적으로 사용하는 =은 같다 이다
하지만 프로그래밍 언어에서는 오른쪽에서 왼쪽으로 가는 화살표와 비슷하다고 생각하면 된다.
오른쪽에 있는 것을 왼쪽에 지정한다는 의미인데 이를 할당 연산자라고 부른다
get_string 함수가 사용자의 이름을 반환하면 그 이름을 answer이라는 변수에 저장하는 것이다

그럼 이 것을 printf 함수로 출력을 해보도록 하겠습니다.
이때 유의할 점은 printf("hello, answer");이 아니라는 점입니다.
이 코드를 실행한다면 answer이 출력이 되어 hello, answer이 그대로 결과로 나옵니다.
우리는 answer이라는 변수에 들어있는 이름을 출력을 해야하기 때문에 %를 사용해 줍니다.
이 때도 어떤 종류의 인자를 받는지 말해줘야 합니다.
우리는 이름이라는 문자열을 받기때문에 string에서의 s를 %뒤에 붙여서 인자를 받아줍니다.
그래서 최종적으로는 printf("hello, %s\n", answer);이 되는 것입니다.

만약 여러 개의 인자를 받는다면 쉼표로 구분해준다.

가장 위에 포함된 cs50.h 파일 안에 string이라는 문자열 형식과 get_string 이라는 함수에 대한 코드가 포함되어 있다. 이 파일을 포함해야만 전체 코드를 컴파일 하고 실행할 수 있다.

터미널창에 아래 명령어를 입력하여 컴파일을 할 수 있다

$make string

이와 같이 작성한 코드를 컴파일하고 실행하면, 사용자에게 입력값을 받고
문장 내에 포함하여 출력하는 프로그램이 된다


조건문과 루프

  • int
  • if
  • while
  • for
int counter = 0;

int는 변수가 정수(integer)라는 것을 알려주는 것이고, counter은 변수의 이름, 0은 그 값에 0을 저장(초기화)하는 것이다
=는 같다는 의미가 아닌, 오른쪽에 있는 값을 왼쪽에 할당하는 의미이다

counter = counter + 1;

즉, counter에 1을 더한 값을 다시 counter에 저장(할당)한다는 의미가 된다

counter += 1;
counter++;

과 같은 의미이다.

if()의 괄호 안에서 검사하고자 하는 조건이 들어가고 {} 안에는 조건을 만족할 때 수행하고자 하는 작업이 들어간다.
여기에서는 조건이 True면 "x is less than y"를 출력하라는 것이다

else를 이용해 처음 조건이 아닌 경우에는 어떤 것을 하라고 적어줄 수 있다.
이 경우에는 첫번째 x<y 조건이 false, 즉 x가 y보다 작지 않을 경우에는
"x is not less than y"를 출력하라고 하는 것이다

else if를 통해 조건을 추가하는데
== 는 일치 연산자 라고 한다

if(x < y), else if (x > y), else if (x == y) 이렇게 3개의 조건문을 사용했습니다.
하지만 여기서 한 가지 굳이 물어볼 필요가 없는 것이 있습니다.
바로 else if (x == y) 입니다.
만약 x가 y보다 작지도 크지도 않다면 우리에게 남은 유일한 가능성은 x와 y가 같다는 것 입니다.
따라서 위의 코드를 수정하면 아래와 같습니다.

이렇게 좀 더 간결하게 만들 수 있습니다.

이렇듯 얼마나 효율적으로 코딩을 하는지, 혹은 얼마나 적은 메모리나 CPU를 사용해서 수행하는지는 정말 중요합니다.

추가로 if, else, else if 뒤에는 세미콜론(;)이 붙지 않은 것을 볼 수 있습니다.
보통 조건과 같은 것들의 끝에는 세미콜론을 붙이지 않습니다.

루프

C에서도 whlie이나 for을 통해 루프를 구현할 수 있다.

while의 경우 while()의 괄호 안에 조건을 넣고 {} 안에 수행할 작업을 포함시키면 된다
C에서 루프를 구현하고 싶다면 성립 조건을 정해줘야한다.
답이 네,참 혹은 1로 나올 수 있는 질문을 해야한다.
가장 간단한 방법은 true를 적는 것이다.

따로 변수를 선언해도 되지만, 아래와 같이 for을 사용하면 for() 안에 각각
(변수 초기화; 변수 조건; 변수 증가)에 해당하는 코드를 넣어서 간단히 표현할 수 있다
가장 먼저 정수 값을 가지는 i라는 변수를 0으로 초기화 하고, i가 50인지 매번 검사를 하고
이를 만족하면 {} 안의 내용을 수행한 수 i를 1씩 증가시킨다는 의미이다.

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

int main(void)  {
    for(int i = 0; i < 10; i++) {
        printf("개발공부는 재미있따!\n");
    }
}
#include <cs50.h>
#include <stdio.h>

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

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

  • char
  • long
  • float
  • double
  • %
  • &&
  • ||

데이터 타입
아래 목록은 변수의 데이터 타입으로 사용할 수 있는 것들입니다.

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를 사용합니다.

CS50 라이브러리 내의 get 함수
CS50 라이브러리는 위와 같은 데이터 타입을 입력값으로 받을 수 있는 아래와 같은 함수들을 포함합니다.
(CS50 라이브러리에서 사용되는 함수이기 때문에 가볍게 알고 가시면 됩니다.)

get_char
get_double
get_float
get_int
get_long
get_string

형식 지정자
printf 함수에서는 각 데이터 타입을 위한 형식 지정자를 사용할 수 있습니다.
지난 강의에서 문자열(string)인 answer 변수의 인자를 %s로 불러온 것을 기억하시나요?
이번에는 여러가지 데이터 타입 마다 사용되는 형식 지정자를 알아보도록 하겠습니다.

%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번째 자리까지 나와 보기에 안 좋습니다.
그럼 이 것을 일부분만 나오게 해볼까요? (소수점 2번째 자리까지 나오게 해보겠습니다.)

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이면 짝수다 그리고 숫자가 3이면 홀수다 숫자가 4면 짝수다 .......(무한반복)....... 128129312는 짝수다
이 방법은 숫자는 무한대이기 때문에 절대 완벽한 코드가 될 수 없습니다.
그럼 어떤 방법이 있을까요? 바로 2로 나누어 나머지가 0이냐 1이냐를 보는 것입니다.
짝수면 나머지가 0이 될 것이고 홀수면 1이 될 것입니다.
if ( n % 2 == 0 ) 을 풀어 쓰면 n을 2로 나누었을 때 나머지가 0이면
printf("even\n"); -> even(짝수)을 출력하라 입니다.
홀수를 출력하는 것은 왜 else if (n % 2 == 1)으로 하지 않았을까요?
왜냐하면 짝수 아니면 홀수 이기 때문에 else로도 충분하기 때문이죠.

주석
C에서는 //로 주석을 달 수 있다

cd : 기본 설정 디렉토리
파일에 진입할땐 cd 파일명
그리고 ls를 입력하면 처음부터 시작할 수 있다

C 표준 라이브러리
CS50 라이브러리 문서
입력과 출력2-[c언어 기초]

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

사용자 정의 함수

#include <stdio.h>

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

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

void를 입력하고 원하는 함수명(cough)을 적은 뒤 괄호 안에 void를 적어줍니다.
그리고 printf로 cough를 출력하는 코드를 작성합니다.
우리가 지금까지 사용하던 'get_int', 'get_string' 등의 함수는 우리가 직접 구현할 필요가 없었습니다.
과거의 어떤 사람들이 모두 구현해두었기 때문입니다.
우리는 함수의 이름을 cough라고 정했습니다.
이제 int main(void)의 안에 cough(함수명)를 사용해보겠습니다.
그럼 우리가 정의해둔 대로 cough가 출력됩니다.

하지만 여기에도 문제가 있습니다.
함수를 1개가 아닌 여러개를 만들수록 main 함수는 아래로 내려가기 때문입니다.
중요한 것이 아래에 있는 것보다 바로 나오는 것이 보기 좋습니다.
그럼 main 함수를 위로 올리고 cough 함수를 내려볼까요?
실행을 해보면 오류가 발생합니다.
main 함수에서 cough() 함수를 사용했습니다.
그런데 cough함수는 아래에 있습니다.
C는 오래되었고 똑똑하지 않기 때문에 아래에 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");
}

void cough(void)를 세미콜론과 함께 위로 올리는 것입니다.
마치 이전에 cough를 봤던 것처럼 C를 속이는 방법입니다.
cough함수를 전부 본 적은 없어도 이름은 본적이 있으니 main 함수에 나올 때까지 코드를 계속 읽도록 하는 것입니다.

이번에는 cough 함수를 좀 더 다재다능하게 만들어 원하는 횟수만큼 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");
    }
}

여기서 맨 아래의 void cough(int n){...} 은 cough 라는 이름의 함수를 우리가 직접 정의한 것입니다.
cough( ) 안의 int n 은 함수가 입력값을 받아서 int 형식을 갖는 n이라는 변수에 저장하겠다는 의미입니다.
그리고 { } 안의 내용을 보면 n번 동안 cough를 출력하는 for 루프가 있습니다.

다시 main 함수 안으로 돌아가보면 cough(3) 이라는 한 줄의 코드를 통해서 3이라는 값을 cough 함수에 전달하고, 궁극적으로는 cough를 세 번 출력할 수 있게 되는 것이죠.

다만 여기서 main 함수를 우리가 정의한 cough 함수보다 위에 위치시키고 싶다면, 예시에서와 같이 void cough(int n);를 먼저 입력해서 cough 라는 함수가 정의되어있음을 알려줘야 합니다.

누군가는 cough 함수를 어떻게 정의했는지 궁금해 할 수 있지만 적어도 여러분은 전혀 알 필요가 없습니다.
그냥 누군가가 구현해 준 기능을 그대로 활용해서 여러분에게 더 흥미로운 프로그램을 만들면 됩니다.

profile
백엔드 프로그래밍을 공부하고 있습니다. AWS, 클라우드 환경에 대해 관심이 많습니다.

0개의 댓글