본문 바로가기
Programming/C

[따배씨] 섹션5. 연산자, 표현식, 문장

by DONGKU 2020. 7. 22.

5.1 반복 루프와의 첫 만남

goto문은 실제 문법으로 잘 쓰이지 않음, 단종된 기술임

#include <stdio.h>

int main()
{
    int n = 1;

label:
    printf("%d\n", n);
    n = n + 1;

    if (n == 10) goto out;

    goto label;

out:

    return 0;
}

5.2 대입 연산자와 몇 가지 용어들

Data object: **메모리에 공간**을 차지하고 있는 데이터들의 형태(이 개념이 객체지향으로 발달)
L-value(object locator value): 메모리 공간을 대표하는 변수명
R-value(value of an expression): 숫자,계산 값
i = 1024;
L-value(i)는 어떤 메모리 공간을 의미하므로 Data object다
R-value(1024)는 상수(literal)이므로 Data object가 아니다
L-value는 임시적으로 R-value 역할을 할 수 있음(i = i + 1)

a+b를 더한 값 자체는 L-value가 아닌 R-value이다. (사용한 후에는 사라지는 값이므로)

5.3 더하기, 빼기, 부호 연산자들

5.4 곱하기 연산자

/* 
* 복리 계산 문제
*/
#include <stdio.h>

int main()
{
    double seed_money, target_money, annual_interest;

    printf("Input seed money : ");
    scanf("%lf", &seed_money);

    printf("Input target money : ");
    scanf("%lf", &target_money);

    printf("Input annual interest(%%) : ");
    scanf("%lf", &annual_interest);

    double fund = seed_money;
    int year_count = 0;

    while (fund < target_money)
    {
        fund += (fund * annual_interest / 100);
        year_count++;
        printf("%lf\n", fund);
    }
    printf("It takes %d years\n", year_count);

    return 0;
}

5.5 나누기 연산자

printf("%d\n", 7 / 2); // 3 // 3.5에서 버림, 컴퓨터는 반올림 해주지 x
printf("%d\n", -7 / 2); // -3 // Truncating toward zero(C99) 0에 가까운쪽으로 절삭
printf("%f\n", 9.0 / 4); // 2.250000 // 컴파일러가 4를 내부적으로 double로 변경

5.6 연산자 우선순위와 표현식 트리

컴파일러가 내부적으로 그래프 구조를 만든 다음 우선순위에 맞춰 계산하는 방식

#include <stdio.h>

int main()
{
    int seconds = 0, minutes = 0, hours = 0;

    printf("Input seconds : ");        // while문 조건 성립위해 입력 밖에서 한번 실행
    scanf("%d", &seconds);

    //TODO: seconds -> hours, minutes, seconds
    while (seconds >= 0)
    {
        minutes = seconds / 60;
        seconds %= 60;

        hours = minutes / 60;
        minutes %= 60;

        // print result
        printf("%d hours, %d minutes, %d seconds\n", hours, minutes, seconds);

        printf("Input seconds : ");        // 이곳에 입력을 해야 마지막값에서 음수입력시 출력없이 바로 조건문으로 들어감
        scanf("%d", &seconds);
    }
    printf("Good bye\n");

    /*
     *  음수를 나눌경우엔 어떻게 되는가.
     *  '%' 연산자에서 '앞'에있는 피연산자(operand)가 음수면 음수값으로 출력.
     */
    int div, mod;

    div = 11 / 5;
    mod = 11 % 5;
    printf("div = %d, mod = %d\n", div, mod);    // div = 2, mod = 1

    div = 11 / -5;
    mod = 11 % -5;
    printf("div = %d, mod = %d\n", div, mod);    // div = -2, mod = 1

    div = -11 / -5;
    mod = -11 % -5;
    printf("div = %d, mod = %d\n", div, mod);    // div = 2, mod = -1

    div = -11 / 5;
    mod = -11 % 5;
    printf("div = %d, mod = %d\n", div, mod);    // div = -2, mod = -1

}

5.8 증가, 감소 연산자

#include <stdio.h>

int main()
{
    int count = 0;
    // ++count or count++
    while (count < 10)    
    {
        printf("%d ", count++);    // 0 1 2 3 4 5 6 7 8 9    // 사용이 끝난 후 증가, 예약하여 증가하는 형태

    }
    printf("\n");
    count = 0;
    while (count < 10)    
    {
        printf("%d ", ++count);    // 1 2 3 4 5 6 7 8 9 10    // 증가한 상태로 사용

    }

    printf("\n");

    int i = 1, j = 1;
    int i_post, pre_j;
/**************************************************
    i_post = i++;
    pre_j = ++j;

    printf("%d %d\n", i, j);            // 1 1	   // Line 25, 26에서 증가됬지만 R-value값이므로 본래 변수에는 영향x

    printf("%d %d\n", i_post, pre_j);    // 1 2    // i_post는 증가하기 전의 값 출력
/**************************************************
    /* ++ and -- affect modifiable l-values */
    int x = 1, y = 1, z;
    z = x * y++;    // (x) * (y++), not (x*y)++
    z = (x * y)++;    // error    (x * y) 는 수정가능한 l-values가 아닌 r-values 이기 때문에 error
    z = 3++;        // error    상수에 대해서도 l-values가 아니기때문에 error
/**************************************************
    /* Bad practices*/
    int n = 1;
    printf("%d %d", n, n * n++);    // 증감 연사자를 사용한 변수를 여러번 사용될 경우 시스템마다 결과가 다르게 나올 수 있다
    int x = n / 2 + 5 * (1 + n++); 
    int y = n++ + n++;                // 눈으로 보기에 헷갈리고 의도가 뭔지 알기 힘들다

    return 0;
}

5.9 표현식과 문장 expressions and statements

표현식(Expressions): 여러가지 연산자와 피연산자가 조합되어 있는 수식

문장(statements): 규칙을 따르는 진술

주효과는 값을 계산하는 것이고, 변수에 대입은 부차적인것(side-effect)

/**************************************************
Sequence Points(;): 값을 언제 계산하는가?

/**************************************************
while문의 조건문 같은 경우는 Sequence Points(;)가 없어도 조건문 계산이 되는 완전한 표현식
컴파일러 입장에서 ++를 괄호 밖에서 계산할지, 세미클론에서 계산을 할지 모호

5.10 순서도 flowchart

5.11 자료형 변환 type conversion

형변환은 중,고급 프로그래머로 갈수록 주의해야한다!

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

int main()
{
    /* promotions(승진) in assignments*/ 
    short s = 64;
    int i = s;
    //short가 int보다 작다.  작은걸 큰거에 대입해줄때는 문제가 안된다.


    float f = 3.14f;
    double d = f;

    /*demotion in assignments*/
    //큰 자료형(double)을 더 작은쪽(float)에 넣으려고 시도하는것을 demotion이라고 한다.
    //  truncation from 'double' to 'float'
    // truncation 절삭.
    d = 1.25;
    f = 1.25; // 1.25f라고 안썼기때문에 double이다.
    //얘는 왜 warning이 안뜰까? 1.25같은 숫자는 
    //double이던 float이던 정밀하게 표현할 수 있다. 1/2^2이기 때문.(2의거듭제곱으로 나누기 가능하기 때문)
    f = 1.123;
    // double일때의 1.123이랑 float일때의 1.123이랑 미묘하게 다르기때문.
    // f = 1.123f;라고 치면 문제 없음.

    /*ranking of types in operations*/
    // long double > double > float (정수형은 실수형보다 랭킹이 낮다)
    // (정수를 실수와 연산하고자하면 정수를 실수로 형변환 한다음에 연산해야한다)
    // (정수간의 랭킹은 조금 덜 중요하지만 중요함, 밑에 같은 줄에 있는 것들은 랭킹이 같다)
    // unsigned long long, long long
    // unsigned long, long
    // unsigned long, long
    // unsigned, int
    // short int, unsigned short int
    // signed char, char, unsigned char
    // _Bool
    d = f + 1.234; // cpu는 서로 다른 자료형을 연산 못함. f를 double로 바꿔주고 계산.
    f = f + 1.234; // 'possilbe lost data.' double을 float에 넣으려고해서 문제.

    /* automatic promotion of function arguments*/
    //자동적으로 이뤄지는 promotion, 함수의 arguments에 적용되는 것.
    // 크게 신경안써도 되는 측면. 위 규칙에 따라 이뤄지는게 대부분.
    // 그렇지 않은 경우가 아래 2경우.
    // 1. Functions without prototypes
    // 2. Variadic functions (printf같은 경우 - 인자가 변할 수 있는경우)
    // 2번은 고급프로그래밍하는 경우. ellipsis.

    /* casting operators*/
    // 위에서는 컴파일러가 알아서 형변환 해주는 경우이고,
    // 이경우는 우리가 형변환을 할거다. 의도적으로 표현하는 경우.
    // casting operator를 사용해서 표기해주는게 좋음. (double), (int)...
    // C++가면 달라지는데, 관습적으로 C스타일의 casting operator도 많이 쓴다.
    d = (double)3.14f;
    // 3.14f는 float인데, (double)을 해주면 expression의 값이 double이 된다.
    i = 1.6 + 1.7; // double을 i(integer)에 대입해주면 절삭된다.
    i = (int)1.6 + (int)1.7; // 실수를 int로 형변환. 
    // 첫번쨰 같은 경우 1.6 +1.7 = 3.3인데 절삭되서 3
    // 두번째 같은 경우 1+1 이 되서 2.

    /*more examples*/
    char c;
    //int i;
    //float f;
    f = i = c = 'A'; // 65
    // int to float. data size는 같은데 유효숫자 갯수가 다르다. 
    // char - int( promotion )
    // int - float (형변환)
    printf("%c %d %f\n", c, i, f);    // A 65 65.000000
    c = c + 2; // 'C', 67
    i = f + 2 * c; // 65.0f + 2*67
    // float(f)와 2*c(int)를 계산하려니 int를 float으로 만들어주고 계산을 하는데,
    // float값을 int(i)에 대입해주려니 자료형이 다르니 truncation해서 넣는다.
    // 그래서 데이터 손실될 수있다.
    printf("%c %d %f \n", c, i, f); // C 199 65.000000
    c = 1106; // demolition, 1106 = 0b10001010010 -> 0b01010010(char는 1바이트이므로 앞부분 짤림) = 1106 % 256(앞부분을 자르는게 나머지 연산자를 적용하는것과 결과가 같음) = 82 = 'R'
    // 1106 - int , char보다 높은 범위의 수 . 그래서 강등당해서 들어감.
    // 100이 truncation되고, 0b01010010이 남아서 이게 10진수로 82. 그게 'R'임.
    // 비트연산자는 나중에 나온다.
    printf("%c\n", c);    // R
    c = 83.99;
    // 84가 나오는게 아니라, 83이 나오고 이게 'S'이다.
    printf("%c\n", c);    // S

    return 0;

}

5.12 함수의 인수와 매개변수

#include <stdio.h>

void draw(int n);    // ANSI function prototype declaration

int main()
{
    int i = 5;
    char c = '#';        // 35
    float f = 7.1f;

    draw(i);
    //draw(c);
    //draw(f);    // float 자료형을 매개변수 자료형이 int인 함수에 넣으려고해 'possible loss of data' 경고

    // 권장하는 방식
    draw((int)c);
    draw((int)f);

    /* Arguments(인수) vs. Parameters(매개변수)*/
    // actual argument, actual parameter -> argument (values): 함수를 '호출'하는 측면
    // formal argument, forma parameter -> parameter (variables): 함수를 '정의'하는 측면

    return 0;
}

void draw(int n)
{
    //while(n > 0)
    //{
    //    printf("*");
    //    n--;
    //}
    while (n-- > 0)
        printf("*");
    printf("\n");
}

댓글