Unit 15. 나머지 연산하기

정수끼리 나눗셈을 하는 경우 몫만 반환하기 때문에 나머지를 구하는 연산도 존재한다.

 

15.1 나머지 연산하기

나머지 연산은 % 연산자를 사용한다. 완전히 나누어지면 나머지는 0이된다.

#include <stdio.h>

int main()
{
    printf("%d\n", 1 % 3);   
    printf("%d\n", 2 % 3);    
    printf("%d\n", 3 % 3);  
    printf("%d\n", 4 % 3);    
    printf("%d\n", 5 % 3);   
    printf("%d\n", 6 % 3);   

    return 0;
}

2 % 3 처럼 나눌 수 없더라도 나머지는 구할 수 있다.(몫은 0, 나머지는 2) 6 % 3 처럼 완전히 나누어지면 나머지 연산의 값은 0이 나온다. 그래서 나머지 연산은 특정 수의 배수인지 확인할 때 주로 사용한다. 나머지 연산은 정수에서만 사용할 수 있고 실수에서 사용하면 컴파일 에러가 발생한다. 또한 5 % 0 처럼 0으로 나눈 나머지는 구할 수 없다.

실수끼리 나누었을 때 나머지는 math.h 헤더 파일의 fmod, fmodf, fmodl 함수를 이용하여 구할 수 있다. fmod는 double, fmodf는 float, fmodl은 long double자료형일 때 사용한다.

#include <stdio.h>
#include <math.h>   

int main()
{
    double num1 = 7.0;
    double num2 = 2.0;
    printf("%f\n", fmod(num1, num2));   

    float num3 = 7.0f;
    float num4 = 2.0f;
    printf("%f\n", fmodf(num3, num4));  

    long double num5 = 7.0l;
    long double num6 = 2.0l;
    printf("%Lf\n", fmodl(num5, num6));  
    return 0;
}

 

15.2 변수 하나에서 나머지 연산하기

#include <stdio.h>
 
int main()
{
    int num1 = 7;
 
    num1 = num1 % 2; 
 
    printf("%d\n", num1);
    return 0;
}

위 연산은 num1에서 2로 나눴을 때 나머지를 num1에 다시 저장한 것이다. 나머지 연산도 할당연산자 %=를 제공한다.

#include <stdio.h>
 
int main()
{
    int num1 = 7;
 
    num1 %= 2; 
 
    printf("%d\n", num1);
    return 0;
}

a % b의 연산을 진행할 때 두 수의 부호가 다르면 앞(a)의 부호를 따른다.

 

15.3 퀴즈 

정답은 c이다.

정답은 b이다.

정답은 d이다.

 

15.4 연습문제 : 3의 배수인지 확인하기

출력 결과가 둘다 0이 나와야 하므로 3과 나눴을 때 나머지 값이여야 한다. 정답은 3이다.

 

16.5 심사문제 : 정수의 각 자리수를 역순으로 출력하기

정답은 다음 코드와 같다.

#include <stdio.h>

int main()
{
    int num;
    
    scanf("%d", &num);
    
    printf("%d ", num % 10);
    num /= 10;
    printf("%d ", num % 10);
    num /= 10;
    printf("%d ", num % 10);
    num /= 10;
    printf("%d ", num % 10);
    num /= 10;
    printf("%d ", num % 10);
    
    return 0;
}

입력 값을 10으로 나눴을 때 나머지를 출력하고 10으로 나눠서 몫만 저장하는 것으로 각 자리를 1의자리부터 출력했다.

 

Unit 16. 자료형의 확장과 축소 알아보기

16.1 자료형의 확장 알아보기

정수와 실수를 연산하면 다음과 같다.

#include <stdio.h>
 
int main()
{
    int num1 = 11;
    float num2 = 4.4f;
 
    printf("%f\n", num1 + num2);   
    printf("%f\n", num1 - num2);    
    printf("%f\n", num1 * num2);   
    printf("%f\n", num1 / num2);    
 
    return 0;
}

결과값은 실수로 나온다. 실수가 정수보다 표현 범위가 넓기 때문이다. C에서는 자료형을 섞어서 사용하면 컴파일러에서 암시적 형변환을 하는데, 자료형의 크기가 큰쪽, 표현 범위가 넓은 쪽으로 변환한다. 이를 형확장이라 한다.

다음은 크기가 다른 정수끼리 연산한 것이다.

#include <stdio.h>
 
int main()
{
    long long num1 = 123456789000;
    int num2 = 10;
 
    printf("%lld\n", num1 + num2);  
    printf("%lld\n", num1 - num2);
    printf("%lld\n", num1 * num2); 
    printf("%lld\n", num1 / num2);    
 
    return 0;
}

4바이트인 int형과 8바이트인 long long형 중 크기가 더 큰 long long 형으로 변환되었다.

 

16.2 자료형의 축소 알아보기

다음과 같이 실수에서 정수로 범위가 적은 쪽으로 변환하면 값의 손실이 일어난다.

#include <stdio.h>
 
int main()
{
    float num1 = 11.0f;
    float num2 = 5.0f;
 
    int num3 = num1 / num2; 
    printf("%d\n", num3); 
 
    return 0;
}

11.0에서 5.0을 나누면 2.2가 나오지만 정수로 형변환 되면서 0.2가 버려졌다. 이와 같이 자료형의 크기가 작은쪽, 표현범위가 좁은쪽으로 변환되는 것을 형 축소라 한다.

형 축소가 일어나면 컴파일할 때 다음과 같이 값의 손실이 일어날 수 있다고 경고가 나온다.

컴파일 경고가 나오지 않게 하려면 형 변환(type conversion, type casting, 타입 캐스팅)을 해야 한다. 형변환은 자료의 손실을 감안하여 구현하거나, 자료형을 숨기고 싶을 때 등 사용한다.

다음은 크기가 다른 정수끼리 연산을 한 것이다.

#include <stdio.h>
 
int main()
{
    char num1 = 28;
    int num2 = 1000000002;
 
    char num3 = num1 + num2;
    printf("%d\n", num3);
  
    return 0;
}

char과 int를 연산하면 char자료형의 크기보다 큰 숫자는 저장할 수 없기 때문에 위 코드의 경우 앞의 숫자들은 버려지고 28 + 2만 저장된다. 버려지는 자릿수를 2진수로 표현하면 다음과 같다.

 

16.3 퀴즈

정답은 d이다.

정답은 c이다.

 

16.4 연습문제 : 문자 출력하기

정답은 char이다.

 

16.5 심사문제 : 실수를 정수로 변환하기

정답은 다음 코드와 같다.

int num2 = num1;
printf("%d\n", num2);

 

Unit 17. if 조건문으로 특정 조건일 때 코드 실행하기

조건문을 사용하면 조건에 따라 다른 코드를 실행할 수 있다.

 

17.1 if 조건문 사용하기

if 조건문은 다음과 같이 괄호 안에 조건식을 지정하여 사용한다.

if (조건식)
{
    코드
}
#include <stdio.h>
 
int main()
{
    int num1 = 10;
 
    if (num1 == 10)    
    {
        printf("10입니다.\n");  
    }
 
    return 0;
}

C에서는 조건문을 if() 형식으로 사용하며 괄호 안에는 조건식이 들어간다. {} 중괄호 안에는 조건식이 만족할 때 실행할 코드가 들어간다.

위 코드의 경우 num1이 10과 같은지 검사하고 있다. ==은 같다를 의미하며 수학의 =(등호)와 같은 의미이다. 위 코드에서 num1은 10으로 조건식을 만족하기 때문에 아래 코드를 실행한다.

파이썬의 if문은 조건식을 괄호로 감싸지 않아도 되고 조건식 끝에 :(클론)을 붙이며, 실행할 코드는 중괄호가 아닌 들여쓰기하여 작성한다는 점에서 문법상의 차이가 있다.

 

17.2 if 조건문과 세미클론

if 조건문을 사용할 때는 조건식 뒤에 ;(세미클론)을 붙이면 안된다.

if (num1 == 10);
{
    printf("10입니다.\n");
}

위 코드와 같이 조건식 뒤에 세미클론을 붙이면 조건식 아래 코드는 조건식과 관계 없는 코드가 된다. 따라서 조건이 만족하지 않아도 항상 아래의 printf함수를 실행하게 된다.

if (num1 == 10);
 
printf("10입니다.\n");

실제로는 위와 같은 형태인 것이다. C에서는 코드를 중괄호로 감싸도 에러가 발생하지 않아서 if 조건문을 무시하고 코드가 동작한다.

 

17.3 if조건문에서 중괄호 생략하기

if 조건문에서 수행할 코드가 한 줄이면 다음과 같이 중괄호를 생략할 수도 있다.

#include <stdio.h>
 
int main()
{
    int num1 = 10;
 
    if (num1 == 10)    
        printf("10입니다.\n");
          
    return 0;
}

위 코드와 같은 조건식도 뒤에 세미클론을 붙이면 안된다. 코드가 두 줄 이상일 때는 중괄호를 생략할 수 없다. 중괄호를 생략하게 되면 다음과 같이 조건이 일치하지 않아도 두번째 코드는 실행되게 된다.

#include <stdio.h>
 
int main()
{
    int num1 = 5;
 
    if (num1 == 10)
        printf("if조건문\n"); 
        printf("10입니다.\n");

    return 0;
}

중괄호가 없을 때 if 조건식의 영향을 받는 것은 한 줄 뿐이다.

 

17.4 if 조건문에서 실수와 문자 비교하기

다음과 같이 정수가 아닌 실수와 문자도 비교할 수 있다.

#include <stdio.h>
 
int main()
{
    float num1 = 0.1f;
    char c1 = 'a';
 
    if (num1 == 0.1f)  // 실수 비교
        printf("0.1입니다.\n");
 
    if (c1 == 'a')     // 문자 비교
        printf("a입니다.\n");
 
    if (c1 == 97)      // 문자를 ASCII 코드로 비교
        printf("a입니다.\n");
 
    return 0;
}

비교할 변수와 값, 변수와 변수는 자료형을 맞춰줘야 한다. 실수는 연산 한 뒤 반올림 오차가 발생할 수 있으니 이를 감안하여 비교해야 한다. 문자는 위 코드와 같이 문자로 비교해도 되고, 아스키 코드값으로 비교해도 된다. 

 

17.5 사용자가 입력한 값에 if 조건문 사용하기

다음과 같이 scanf 함수를 사용하여 사용자의 입력을 받고 입력 받은 값을 if문으로 비교할 수 있다.

#include <stdio.h>

int main()
{
    int num1;
    scanf("%d", &num1);

    if(num1 == 10)
    {
        printf("10입니다.\n");
    }
    if(num1 == 20)
    {
        printf("20입니다.\n");
    }

    return 0;
}

조건에 만족하는 것이 있으면 해당하는 코드를 수행하고 만족하는 것이 없으면 아무 코드도 수행하지 않는다.

 

17.6 퀴즈

정답은 e이다.

정답은 a, c이다.

정답은 b, d이다.

 

17.7 연습문제 : if조건문 사용하기

c1에 'k'가 저장되어 있으므로 조건을 만족시키려면 정답은 == 'k' 이다.

 

17.8 심사문제 : 청소년 콘텐츠 관람 제한하기

정답은 다음 코드와 같다.

#include <stdio.h>

int main()
{
    int age;
    scanf("%d\n", &age);
    
    if(age < 18)
    {
        printf("청소년 관람 불가\n");
    }
    return 0;
}

 

Unit 18. else를 사용하여 두 방향으로 분기하기

if는 분기를 위한 문법이다. 분기는 "둘 이상 갈라지다" 라는 뜻으로 프로그램의 흐름을 둘 이상으로 나누는 것을 말한다.

if에 else를 사용하면 프로그램을 두 방향으로 분기하여 조건식이 만족할 때와 만족하지 않을 때 각각 다른 코드를 실행할 수 있다.

 

18.1 else 사용하기

else는 if 조건문 뒤에 오며 단독으로 사용할 수는 없다. 사용 형태는 다음과 같다.

if (조건식)
{
    코드1
}
else
{
    코드2
}
#include <stdio.h>
 
int main()
{
    int num1 = 20;
 
    if (num1 == 10)
    {
        printf("10입니다.\n");
    }
    else  
    {
        printf("10이 아닙니다.\n");
    }
 
    return 0;
}

위 코드에는 num1이 20이라 if 조건식을 만족하지 않기 때문에 else의 코드가 실행되었다.

if 조건식이 만족하면 참(True), 만족하지 않으면 거짓(False)이라고 부르는데, 조건식이 참이면 if의 코드가 실행되고, 거짓이면 else의 코드가 실행된다.

 

18.2 else와 세미클론

if 처럼 else도 뒤에 세미클론을 붙이지 않도록 주의해야 한다. 세미클론을 붙이면 그 아래 코드는 else와는 관계없는 코드가 되어 버려서 조건식 결과와는 관계 없이 항상 실행되게 된다.

 

18.3 else에서 중괄호 생략하기

else도 실행할 코드가 한 줄이면 중괄호를 생략할 수 있다.

#include <stdio.h>
 
int main()
{
    int num1 = 20;
 
    if (num1 == 10)
        printf("10입니다.\n");
    else  
        printf("10이 아닙니다.\n");
 
    return 0;
}

if, else로 실행할 코드가 두 줄 이상이면 컴파일 에러가 발생한다.

#include <stdio.h>
 
int main()
{
    int num1 = 20;
 
    if (num1 == 10)
        printf("1\n");
        printf("10입니다.\n");
    else
        printf("1\n");  
        printf("10이 아닙니다.\n");
 
    return 0;
}

따라서 두 줄 이상이면 반드시 중괄호로 묶어줘야 한다.

다음과 같이 if만 중괄호로 묶고 else의 코드는 묶지 않았을 경우 컴파일 에러는 발생하지 않지만 조건과 관계없이 두번째 이하의 코드는 항상 실행된다.

#include <stdio.h>
 
int main()
{
    int num1 = 10;
 
    if (num1 == 10)
    {
        printf("1\n");
        printf("10입니다.\n");
    }
    else
        printf("1\n");  
        printf("10이 아닙니다.\n");
 
    return 0;
}

 

18.4 if 조건문의 동작 방식 알아보기

if는 0일때 거짓, 0이 아닐때 참으로 동작한다.

#include <stdio.h>
 
int main()
{
    if (5)    
        printf("참\n");
    else
        printf("거짓\n");
 
    return 0;
}

조건식에 5를 넣었는데도 참으로 동작한다. 0이아닌 모든 수를 넣으면 참으로 동작하며, 실수도 0.0f가 아닌 값들은 다 참이다.

#include <stdio.h>
 
int main()
{
    if (0)    
        printf("참\n");
    else
        printf("거짓\n");
 
    return 0;
}

0은 거짓이기 때문에 위와 같이 else 아래의 코드가 실행되어 거짓이 출력된다.

#include <stdio.h>
 
int main()
{
    int num1 = 5;

    if(num1 = 10)
        printf("10입니다.\n");
 
    return 0;
}

위 코드에서는 조건식에 =(할당연산자)를 사용하고 있다. 할당 연산자를 사용하게 되면 num1에 10이 할당되어 10이 되고, 10은 0이 아니라 참이기 때문에 if 아래의 코드가 실행된다. 이러한 실수는 컴파일 에러가 발생하지 않아 잡아내기 힘들기 때문에 주의해야 한다. 이런 실수를 줄이기 위해 다음과 같은 코드를 사용하기도 한다.

if (10 == num1)
    printf("10입니다.\n");

조건식에서 변수를 뒤에 두면 10은 리터럴이기 때문에 값을 저장할 수  없어 만약 =(할당연산자)를 사용하게 되면 컴파일 에러가 발생한다.

 

18.5 조건식을 여러개 지정하기

if 조건문은 논리연산을 사용하여 조건식을 여러개 지정할 수 있다.

#include <stdio.h>

int main()
{
    int num1 = 10;
    int num2 = 20;

    if (num1 == 10 && num2 == 20)    
        printf("참\n");
    else
        printf("거짓\n");

    return 0;
}

&&은 논리 연산자이며 "두 식이 모두 만족할 때"를 의미한다. 위 코드에서는 num1이 10인것과 num2가 20인것이 모두 만족하여 참을 출력했다.

이 코드는 다음과 같이 if 조건문 안에 다시 if 조건문을 넣는 구조로도 똑같이 사용할 수 있다.

#include <stdio.h>

int main()
{
    int num1 = 10;
    int num2 = 20;

    if (num1 == 10)
        if(num2 == 20)    
            printf("참\n");
        else
            printf("거짓\n");
    else
        printf("거짓\n");

    return 0;
}

if 안에 들어와서 다시 if를 만족해야 하므로 &&와 같은 동작을 한다. 안쪽에 있는 if 조건문이 수행할 코드가 한 줄일 경우 위와 같이 바깥쪽과 안쪽의 중괄호를 모두 생략할 수 있다.

 

18.6 퀴즈

정답은 b이다.

정답은 e이다. 세미클론을 붙이면 안된다.

정답은 거짓이다.

정답은 c,e이다.

정답은 b이다.

 

18.7 연습문제 : else 사용하기

C에서 0이아니면 모두 참이므로 정답은 0이다.

 

18.8 연습문제 : 합격 여부 판단하기

정답은 writtenTest >= 80 && toeic >= 850 이다.

 

18.9 심사문제 : else 사용하기

정답은 다음 코드와 같다.

#include <stdio.h>

int main()
{
    char c1;
    scanf("%c", &c1);
    
    if(c1 == 'a')
        printf("a입니다.\n");
    else
        printf("a가 아닙니다.\n");
    
    return 0;
}

 

18.10 심사문제 : 합격 여부 판단하기

정답은 다음 코드와 같다.

 #include <stdio.h>

int main()
{
    int kor, eng, math, sci, avg;
    scanf("%d %d %d %d", &kor, &eng, &math, &sci);
    
    if(kor <= 100 && kor >= 0 && eng <= 100 && eng >= 0 && math <= 100 && math >= 0 && sci <= 100 && sci >= 0)
    {
        avg = (kor + eng + math + sci) / 4;
        if(avg >= 85)
            printf("합격\n");
        else
            printf("불합격\n");
    }
    else
    {
        printf("잘못된 점수\n");
    }
        
    return 0;
}

 

Unit 19. else if를 사용하여 여러 방향으로 분기하기

프로그램을 만들다 보면 두 가지 이상의 다양한 상황이 발생하며 이러한 상황들을 처리할 필요가 있다.

else if로 조건식을 여러개 지정하여 각 조건마다 다른 코드를 실행할 수 있다

파이썬에서는 else if 와 동일한 역할을 하는 키워드로 elif를 사용했다.

 

19.1 else if 사용하기

else if는 else인 상태에서 조건식을 지정할 때 사용하며 단독으로 사용할 수는 없다.

if (조건식)
{
    코드1
}
else if (조건식)
{
    코드2
}
#include <stdio.h>

int main()
{
    int num1 = 20;

    if (num1 == 10)
        printf("10입니다.\n");
    else if (num1 == 20)    
        printf("20입니다.\n");

    return 0;
}

위 코드는 num1 이 10인지 검사하여 맞으면 10입니다. 를 출력하고, 거짓이면 그 뒤 else if의 조건식을 검사한다. else의 조건식이 참이면 20입니다.를 출력하고 거짓이면 아무것도 출력하지 않는다. else if에 조건식을 지정하지 않으면 컴파일 에러가 발생한다. else if도 끝에 세미클론을 붙이면 안된다.

 

19.2 if, else if, else를 모두 사용하기

else if는 else와 함께 사용할 수 있다. 

#include <stdio.h>

int main()
{
    int num1 = 30;

    if (num1 == 10)
        printf("10입니다.\n");
    else if (num1 == 20)    
        printf("20입니다.\n");
    else
        printf("10도 20도 아니다.\n");

    return 0;
}

위 코드는 if 조건식과 else if 조건식이 모두 거짓일 때 else의 코드가 실행된다. 

if와 else는 한번만 사용할 수 있지만 else if는 여러번 사용할 수 있다.

else if 앞에 else가 오면 컴파일 에러가 발생한다.

 

19.3 퀴즈

정답은 b,c,e이다.

정답은 e이다. else if에는 조건식이 있어야 한다.

 

19.4 연습문제 : if, else if, else 모두 사용하기

c가 출력됬으므로 정답은 'c'이다.

 

19.5 심사문제 : 교통카드 시스템 만들기

정답은 다음 코드와 같다.

if(7 <= age && age <= 12)
    balance -= 450;
else if(13 <= age && age <= 18)
    balance -= 720;
else
    balance -= 1200;

 

Unit 20. 비교연산자와 삼항 연산자 사용하기

비교연산자는 값을 비교할 때 사용하며 종류는 다음과 같다.

삼항연산자는 연산에 필요한 값이 3개인 연산자이다. 

 

20.1 비교연산자 사용하기

#include <stdio.h>
 
int main()
{
    int num1 = 10;
 
    printf("%d\n", num1 == 10);  
    printf("%d\n", num1 != 5);   
 
    printf("%d\n", num1 > 10);     
    printf("%d\n", num1 < 10);   
 
    printf("%d\n", num1 >= 10);    
    printf("%d\n", num1 <= 10);   
 
    return 0;
}

비교 연산자는 참이면 1, 거짓이면 0이 나온다.

 

20.2 삼항 연산자 사용하기

삼항연산자는 다음과 같은 형식으로 사용한다.

    변수(조건식) ? 값1 : 값2

#include <stdio.h> 

int main()
{
    int num1 = 5;
    int num2;
 
    num2 = num1 ? 100 : 200; 
    printf("%d\n", num2);  
    
    return 0;
}

삼항 연산자는 참, 거짓을 판단할 변수나 조건식을 ? 앞에 지정하고 ? 뒤에 참과 거짓일 때 사용할 값을 나열한다. 각 값은 : 으로 구분하며 앞의 값은 참일때 반환하고, 뒤의 값은 거짓일 때 반환한다.

위 코드에서 num1 은 5로 0이 아니기 때문에 참이므로 : 앞의 값인 100이 num2에 저장되었다.

다음과 같이 비교연산자를 사용한 조건식을 삼항연산자와 함께 사용할 수 있다.

#include <stdio.h> 

int main()
{
    int num1 = 5;
    int num2;
 
    num2 = num1 == 10 ? 100 : 200; 
    printf("%d\n", num2);  

    return 0;
}

num1은 5이기 때문에 조건식이 거짓이라 num2 에는 : 뒤의 값인 200이 저장되었다.

삼항연산자는 if 조건문을 짧게 표현할 수 있다는 장점이 있지만, 축약된 형식이기 때문에 가독성을 해칠 수 있다. 가독성을 해치지 않으면서 코드를 간결하게 표현할 수 있을 때만 삼항 연산자를 사용하는 것이 좋다.

 

20.3 if 조건문과 비교연산자 사용하기

#include <stdio.h>
 
int main()
{
    int num1 = 10;
 
    if (num1 == 10)
        printf("10입니다.\n");
 
    if (num1 != 5)   
        printf("5가 아닙니다.\n");
 
    if (num1 > 10)   
        printf("10보다 큽니다.\n");
 
    if (num1 < 10)
        printf("10보다 작습니다.\n");
 
    if (num1 >= 10)   
        printf("10보다 크거나 같습니다.\n");
 
    if (num1 <= 10)  
        printf("10보다 작거나 같습니다.\n");
 
    return 0;
}

비교의 결과가 참이면 if문의 코드가 실행되고, 거짓이면 실행되지 않는다.

다음과 같이 정수 뿐 아니라 실수와 문자도 비교할 수 있다.

#include <stdio.h>
 
int main()
{
    float num1 = 0.1f;
    char c1 = 'a';
 
    if (num1 >= 0.09f) 
        printf("0.09보다 크거나 같습니다.\n");
 
    if (c1 == 'a')  
        printf("a입니다.\n");
 
    if (c1 == 97)     
        printf("97입니다.\n");
 
    if (c1 < 'b')   
        printf("b보다 작습니다.\n");
    
    return 0;
}

문자 자료형도 c1 == 'a'와 같이 문자 그대로 비교할 수 있고, 문자 자료형도 정수이기 때문에 숫자로 비교할 수도 있다.

실수는 반올림 오차가 존재하므로 == 연산자로 정확한 값을 비교하는 것은 위험할 수 도 있다.

 

20.4 함수 안에서 삼항 연산자 사용하기

#include <stdio.h>

int main()
{
    int num1 = 5;

    printf("%s\n", num1 == 10 ? "10입니다." : "10이 아닙니다."); 
    return 0;
}

printf함수로 삼항 연산자의 결과가 출력되고 있다.

위 코드와 같이 삼항연산자는 참/거짓을 판단하여 결과값을 함수에 전달할 때 유용하게 사용할 수 있다.

 

20.5 퀴즈

정답은 c, d이다.

정답은 c이다.

정답은 d이다.

정답은 c,d 이다.

 

20.6 연습문제 : 비교 연산자 사용하기

다 참이 나와야 하므로 정답은 >, ==, < 이다.

 

20.7 연습문제 : 삼항 연산자 사용하기

정답은 >, ?, : 이다.

 

20.8 심사문제 : 비교 연산자 사용하기

정답은 다음 코드와 같다.

#include <stdio.h>

int main()
{
    char c1;
    scanf("%c", &c1);
    
    if(c1 != 'k')
        printf("참\n");
    else
        printf("거짓\n");
        
    if(c1 > 'h')
        printf("참\n");
    else
        printf("거짓\n");
    
    if(c1 <= 'o')
        printf("참\n");
    else
        printf("거짓\n");
    
    return 0;
}

 

20.9 심사문제 : 삼항 연산자 사용하기

정답은 다음 코드와 같다.

num1 != 7 ? 1 : 2

 

Unit 21. 논리 연산자 사용하기

논리 연산자는 조건식이나 값을 논리적으로 판단한다. 논리값 거짓은 0, 참은 0이 아닌 값이며 보통 1을 많이 사용한다. 다음은 논리 연산자들이다.

 

21.1 AND 연산자 사용하기

AND연산자는 &&으로 사용한다.

#include <stdio.h>
 
int main()
{
    printf("%d\n", 1 && 1);   
    printf("%d\n", 1 && 0);   
    printf("%d\n", 0 && 1);   
    printf("%d\n", 0 && 0);  
 
    printf("%d\n", 2 && 3);   
 
    return 0;
}

&&는 두 값이 모두 참이여야 참이 나온다. 따라서 1 && 1만 참이 된다. 또한 C에서는 0이 아닌 값은 모두 참이므로 2 && 3도 참이다. 

논리 연산에서 중요한 것은 단락평가이다. 단락평가는 첫번째 값 만으로 결과가 확실할 때 두번째 값은 평가하지 않는 것이다. 0 && 1의 경우 첫번째 값이 거짓이기 때문에 두번째 값은 확인하지 않고 바로 거짓으로 결정한다.

 

21.2 OR 연산자 사용하기

OR 연산자는 || 으로 사용한다.

#include <stdio.h>
 
int main()
{
    printf("%d\n", 1 || 1); 
    printf("%d\n", 1 || 0);  
    printf("%d\n", 0 || 1);   
    printf("%d\n", 0 || 0);  
 
    printf("%d\n", 2 || 3);
    
    return 0;
}

||은 두 값중 하나라도 참이면 결과가 참이다. 따라서 0 || 0만 거짓이다. OR연산은 두 값중 하나만 참이면 참이므로 첫번째 값이 참이면 두 번째 값은 확인하지 않고 참으로 결정한다.

 

21.3 NOT 연산자 사용하기

NOT 연산자는 ! 으로 사용한다.

#include <stdio.h>
 
int main()
{
    printf("%d\n", !1);    
    printf("%d\n", !0);  
 
    printf("%d\n", !3);    
 
    return 0;
}

NOT연산자는 변수, 값, 함수 앞에 !를 붙인다. !은 참은 거짓으로, 거짓은 참으로 논리값을 뒤집는다. 

 

21.4 조건식과 논리 연산자 사용하기

다음과 같이 조건식도 논리연산자로 판단할 수 있다.

#include <stdio.h>
 
int main()
{
    int num1 = 20;
    int num2 = 10;
    int num3 = 30;
    int num4 = 15;
 
    printf("%d\n", num1 > num2 && num3 > num4); 
    printf("%d\n", num1 > num2 && num3 < num4);  
    
    printf("%d\n", num1 > num2 || num3 < num4);  
    printf("%d\n", num1 < num2 || num3 < num4);  
 
    printf("%d\n", !(num1 > num2));    
 
    return 0;
}

비교연산자로 대소 관계를 비교한 후 논리연산자로 참, 거짓을 판단하였다. 

비교연산자와 논리연산자가 연달아 나오면 알아보기 어렵기 때문에 괄호를 이용하여 알아보기 쉽게 하는 것도 좋다.

printf("%d\n", (num1 > num2) || (num3 < num4));  
(age >= 19) && (age < 65)

위와 같은 경우 age가 19 미만이면 단락평가로 두 번째 조건은 검사하지 않는다.

 

21.5 if조건문과 논리 연산자 사용하기

#include <stdio.h>
 
int main()
{
    int num1 = 1;
    int num2 = 0;
 
    if (num1 && num2)     
        printf("참\n");
    else
        printf("거짓\n"); 
 
    if (num1 || num2)      
        printf("참\n");    
    else
        printf("거짓\n");
 
    if (!num1)        
        printf("참\n");
    else
        printf("거짓\n");  
 
    return 0;
}

각 변수에 1과 0이 들어있으므로 AND연산의 결과는 거짓이고, OR연산의 결과는 참이다. 

if 조건문 안에서도 단락 평가를 하기 때문에 num1 || num2의 경우 num1이 1이기 때문에 num2는 검사하지 않고 참으로 결정하여 if의 코드를 실행한다.

int num1 = 0;
int num2 = 10;

if ((num1 != 0) && (num2 / num1) < 20)    
    printf("참\n");
else
    printf("거짓\n");

위 코드의 경우 정수를 0으로 나누면 에러가 발생하지만 나눗셈 연산 전에 num != 0으로 num이 0이 아닌지 검사하여 에러를 예방할 수 있다. 단락 평가를 통해 num1이 0이라면 뒤 조건은 검사하지 않고 거짓으로 결정한다.

 

21.6 삼항연산자에 논리 연산자 사용하기

#include <stdio.h>
 
int main()
{
    int num1 = 1;
    int num2 = 0;
 
    printf("%s\n", num1 && num2 ? "참" : "거짓");    
    printf("%s\n", num1 || num2 ? "참" : "거짓");   
 
    return 0;
}

위 코드와 같이 삼항 연산자 안에도 논리 연산자를 사용할 수 있다. num1 은 1이고, num2 는 0이므로 and연산은 거짓이고, or 연산은 참이다.

 

21.7 퀴즈

정답은 b, d, e이다.

정답은 a, c, e 이다.

정답은 d이다.

정답은 b, c, e이다.

 

21.8 연습문제 : 논리 연산자 사용하기

정답은 ||, ||, num2 이다.

 

21.9 심사문제 : 논리 연산자 사용하기

정답은 다음 코드와 같다.

#include <stdio.h>

int main(void)
{
    int n1, n2;
    scanf("%d %d", &n1, &n2);
    
    if(n1 && n2)
        printf("참\n");
    else
        printf("거짓\n");
    if(n1 || n2)
        printf("참\n");
    else
        printf("거짓\n");
    if(!n1)
        printf("참\n");
    else
        printf("거짓\n");
        
    return 0;
}

 

Unit 8. 실수 자료형 사용하기

소숫점을 표현할 수  있는 실수 자료형의 크기와 저장할 수 있는 값의 범위는 다음과 같다.

파이썬에서 실수 자료형은 float  하나였는데 C에서는 위 3개의 자료형이 존재한다.

지수 표기법은 아주 큰 숫자나 아주 작은 숫자를 표현할 때 사용한다. 실수e + 지수는 실수 * 10의 거듭제곱이다. 또한 실수e - 지수는 실수 * 1/10의 거듭제곱이다. 

long double의 크기는 운영체제의 플랫폼에 따라 다음과 같이 다르다.

컴퓨터에서는 값을 0과 1로 저장하기 때문에 실수고 0과 1로 저장해야 한다. 실수와 소수점을 2진수로 표현하는 방식을 부동소수점 표현 방식이라 한다. 부동소수점 방식은 자료형의 일정 부분을 비트 단위로 나누어 부호, 가수(significand), 기수(base), 지수(exponent)를 저장하여 실수를 표현한다. 

다음과 같이 기수(n)을 지수(p)만큼 거듭제곱한 값을 가수(m)와 곱하는 방식이다. 가수는 2로 고정되어 있으며 2 자체는 따로 저장하지 않는다.

유효자릿수는 실수를 일정 자릿수만큼 표현할 수 있는 것이다. 만약 유효자릿수가 7이면 0.123456789는 반올림하여 0.123457로 표현된다. 정수부분 1자리와 소수부분 6자리로 7자리가 표현되는 것이다.

 

8.1 실수형 변수 선언하기

#include <stdio.h>

int main()
{
    float num1 = 0.1f;  // float는 숫자 뒤에 f를 붙임
    double num2 = 3867.215820;  // double는 숫자 뒤에 아무것도 붙이지 않음
    long double num3 = 9.327513l;   // long double는 숫자 뒤에 l을 붙임

    printf("%f %f %Lf\n", num1, num2, num3);
    return 0;
}

float에서 .1f, 1.f처럼 소숫점 앞 또는 뒤의 0은 생략할 수 있다.

실수를 출력할 때는 서식문자로 float와 double은 %f를, long double 는 %Lf를 사용한다.

지수표기법으로 실수를 저장하는 코드는 다음과 같다.

#include <stdio.h>

int main()
{
    float num1 = 3.e5f; // 30000
    double num2 = -1.3827e-2;   // -0.013827
    long double num3 = 5.21e+9l;    // 5210000000

    printf("%f %f %f %Lf\n", num1, num2, num3);
    printf("%e %e %Le\n", num1, num2, num3);
    return 0;
}

지수 표기법으로 실수를 출력할 때는 float, double는 서식지정자 %e를 사용하고, long double는 %Le를 사용한다. e뒤의 지수가 양수이면 num1과 같이 +기호를 생략할 수도 있다.

 

8.2 자료형 크기 구하기

다음과 같이 sizeof연산자를 이용하여 실수 자료형의 크기를 구할 수 있다.

#include <stdio.h>

int main()
{
    float num1 = 0.0f;
    double num2 = 0.0;
    long double num3 = 0.0l;

    printf("float : %d, double : %d, long double : %d",
    sizeof(num1),
    sizeof(num2),
    sizeof(num3)
    );

    return 0;
}

윈도우 운영체제에서 각 자료형의 크기는 다음과 같다.

또한 mac OS에서의 각 자료형의 크기는 다음과 같다.

리눅스에서도 long double는 16바이트 이다.

 

8.3 최솟값과 최댓값 표현하기

실수 자료형의 양수 최솟값과 최댓값을 표현하는 방법은 다음과 같다. float.h 헤더파일에 실수 자료형별로 양수 최솟값과 최댓값이 정의되어 있다.

#include <stdio.h>
#include <float.h>

int main()
{
    float num1 = FLT_MIN;   // float의 양수 최솟값
    float num2 = FLT_MAX;   // float의 양수 최댓값
    double num3 = DBL_MIN;  // double의 양수 최솟값
    double num4 = DBL_MAX;  // double의 양수 최댓값
    long double num5 = LDBL_MIN;    // long double의 양수 최솟값
    long double num6 = LDBL_MAX;    // ling double의 양수 최댓값

    printf("%.40f %.2f\n", num1, num2);
    printf("%e %e\n", num3, num4);
    printf("%Le %Le\n", num5, num6);
    return 0;
}

서식지정자를 사용할때 %.40f, %.2f와 같이 .뒤에 숫자를 지정하면 해당 숫자만큼 출력하는 소숫점 자릿수를 설정할 수 있다.

double, long double의 최소, 최댓값들은 소수점 자리가 매우 길어 지수 표기법으로 출력하였다.

 

8.4 오버플로우와 언더플로우 알아보기

다음과 같이 실수 자료형도 오버플로우와 언더플로우가 발생할 수 있다.

#include <stdio.h>
#include <float.h>

int main()
{
    float num1 = FLT_MIN;
    float num2 = FLT_MAX;

    num1 = num1 / 100000000.0f;
    num2 = num2 * 1000.0f;

    printf("%e %e\n",num1, num2);
    return 0;
}

FLT_MIN을 10000000.0과 같이 아주 큰 값과 나누면 아주 작은 수가 되면서 언더플로우가 발생한다. C에서는 언더플로우를 0 또는 쓰레기값으로 처리한다. 

FLT_MAX에 1000.0을 곱하면 저장할 수 있는 범위를 넘어서 오버플로우가 발생하게  된다. 실수는 오버플로우 발생 시 최솟값으로 되돌아가지 않고 무한대(inf)가 된다. 

 

8.5 퀴즈

정답은 d이다.

정답은 e이다.

정답은 d이다. float는 실수 뒤에 f를 붙여야 한다.

정답은 b이다.

정답은 c이다.

 

8.6 연습문제 : 실수형 변수 선언하기

정답은 밑줄 순서대로 float, long double, double이다.

 

8.7 연습문제 : 자료형 크기 구하기

num1의 크기는 8이고, num2의 크기는 4이므로 정답은 순서대로 double, float이다.

 

8.8 연습문제 : 최솟값과 최댓값 표현하기

정답은 다음 코드와 같다.

#include <float.h>
DBL_MIN
LDBL_MAX

 

8.9 언더플로우

num1을 큰 수로 나누면 되므로 정답은 / 10000000.0f 이다.

 

8.10 심사문제 : 실수형 변수 선언과 자료형 크기 구하기

num1 의 크기는 4이니 float 이고, num2의 크기는 8이기 때문에 double이다. 정답은 다음 코드와 같다.

float num1 = 1.8f;
double num2 = 2.9;

 

8.11 심사문제 : 최솟값과 최댓값 표현하기

정답은 다음 코드와 같다.

doubleMin = DBL_MIN;
doubleMax = DBL_MAX;
longDoubleMin = LDBL_MIN;
longDoubleMax = LDBL_MAX;

 

8.12 심사문제 : 오버플로우

정답은 - FLT_MAX 이다.

 

Unit 9. 문자 자료형 사용하기

C에서는 정수 자료형 char을 사용하여 문자 1개를 저장한다. 문자 자료형의 저장 범위와 크기는 다음과 같다.

C에서 문자를 저장할 때는 아스키 코드이 문자에 해당하는 정수 값을 저장한다. 다음은 아스키 코드표 이다.

65(0x41)부터 90(0x5A)까지 알파벳 대문자를 나타내고, 97(0x61)부터 122(0x7A)까지 알파벳 소문자를 나타낸다. 나머지 값들은 공백, 특수문자, 숫자 등을 나타낸다. 

C에서 문자는 다음과 같이 ' '(작은따옴표)로 묶어서 표현한다.

char c1 = 'a';

작은따옴표는 문자 하나만 묶을 수 있고, 두개 이상은 묶을 수 없다.

정수 자료형에 2바이트 값을 저장할 때는 다음과 같이 문자 두 개를 작은 따옴표로 묶기도 한다.

unsigned short magic = 'BA';

파이썬에서는 문자열로 여러개의 문자를 다른 선언 없이 변수에 저장할 수 있었지만 C는 이러한 것들이 불가능한 것 같다.

 

9.1 문자 변수 선언하기

#include <stdio.h>

int main()
{
    char c1 = 'a';
    char c2 = 'b';

    printf("%c %d\n",c1 ,c1);
    printf("%c %d\n", c1, c2);
    return 0;
}

변수나 문자를 출력할 때는 %c 서식지정자를 사용한다. 서식 지정자로 %d를 사용하면 char 변수에 저장된 문자의 아스키 코드값이 10진수로 출력된다. 

다음과 같이 작은따옴표로 문자를 저장하지 않고, 아스키 코드에 해당하는 정수로 문자를 출력할 수 있다.

#include <stdio.h>

int main()
{
    char c1 = 97;
    char c2 = 98;

    printf("%c %d\n",c1 ,c1);
    printf("%c %d\n", c2, c2);
    return 0;
}

다음과 같이 아스키 코드값 16진수를 넣어서도 문자 자료형을 사용할 수 있다.

#include <stdio.h>

int main()
{
    char c1 = 0x61;
    char c2 = 0x62;

    printf("%c %d 0x%x\n",c1 ,c1, c1);
    printf("%c %d 0x%x\n", c2, c2, c2);
    return 0;
}

16진수를 출력하려면 서식지정자 %x를 사용한다.(%X는 16진수의 알파벳을 대문자로 표시) 16진수만 출력하면 10진수와 구분하기 힘드므로 앞에 0x를 붙인다.

문자 자료형에 같은 숫자를 저장해도 문자 '0'과 숫자 0은 다르다.

#include <stdio.h>

int main()
{
    char c1 = '0';
    char c2 = 0;

    printf("%c %d\n",c1 ,c1);
    printf("%c %d\n", c2, c2);
    return 0;
}

'0'을 10진수로 출력해보면 '0'의 아스키 코드값인 48이 나오며, 0을 문자로 출력하면 아스키 코드 0은 널문자를 뜻하므로 아무것도 출력되지 않는다.

 

9.2 문자로 연산하기

문자도 아스키 코드의 정수로 저장되므로 정수처럼 덧셈, 뺄셈을 할 수 있다.

#include <stdio.h>

int main()
{
    printf("%c %d\n", 'a'+1, 'a'+1);
    printf("%c %d\n", 97+1, 97+1);
    return 0;
}

'a'의 아스키코드 값은 97이고, 'b'의 아스키코드 값은 98이기 때문에 'a' + 1은 'b'가 출력된다. 또한 97은 'a'이고, 98은 'b'이기 때문에 97 + 1 의 값은 'b'가 출력된다. char로 저장한 변수에 정수를 더하거나 빼도 결과는 같다.

 

9.3 제어문자 사용하기

문자 자료형에는 \n 과 같은 제어문자도 지정할 수 있다.

#include <stdio.h>

int main()
{
    char c1 = 'a';
    char c2 = 'b'; 
    char lineFeed = '\n';

    printf("%c%c%c%c", c1, lineFeed, c2, lineFeed);
    return 0;
}

제어문자 '\n'이 저장된 변수 lineFeed를 %c로 출력하면 줄바꿈이 되어 위와 같이 출력된다. 다음은 자주 접하게 되는 제어문자의 아스키 코드 이다.

다음은 제어문자의 아스키 코드를 출력한 것이다.

#include <stdio.h>

int main()
{
    char lineFeed = '\n';

    printf("%d 0x%x\n", lineFeed, lineFeed);
    return 0;
}

제어문자 \n의 10진수 값과 16진수 값인 10과 0xa가 출력되었다.

 

9.4 퀴즈

정답은 c이다.

정답은 e이다.

정답은 b이다.

 

9.5 연습문제 : 제어문자 사용하기

정답은 '\t'이다. 탭을 의미하는 제어문자는 \t이다.

 

9.6 연습문제 : 정수 숫자를 문자로 변환하기

출력을 %c로 하고 있고, 아스키코드로 2는 50이므로 48씩 더하면 된다. 따라서 정답은 +48, +48이다.

 

9.7 심사문제 : 제어문자 사용하기

c1 은 탭, c2는 줄바꿈, c3는 탭이 들어가야 하므로 정답은 다음과 같다.

c1 = '\t';
c2 = '\n';
c3 = '\t';

 

9.8 심사문제 : 알파벳 소문자를 대문자로 변환하기

a와 A는 아스키코드로 32 차이가 나므로 정답은 -32 이다.

 

Unit 10. 상수 사용하기

상수는 변하지 않는 값을 의미한다. 변수는 한 번 선언하고 값을 계속 바꿀 수 있지만, 상수는 선언되면 값을 바꿀 수 없다.

const int con1 = 10;

위와 같은 코드가 있을 때 con1을 상수라 하고, 10을 리터럴이라 한다. 리터럴은 값 자체를 의미하고, 상수는 변수처럼 리터럴이 저장된 공간이다. 상수는 값을 바꾸는 것을 방지하기 위해 사용하며 코드의 의도를 명확하게 만들 수 있다.

 

10.1 리터럴 사용하기

#include <stdio.h>

int main()
{
    printf("%d\n", 10);       
    printf("%f\n", 0.1f);               
    printf("%c\n", 'a');              
    printf("%s\n", "Hello, world!");    

    return 0;
}

위 코드와 같이 변수에 저장하지 않고 값을 그대로 사용하는 것이 리터럴이다. 리터럴은 표기 방법을 반드시 지켜야 한다. 문자는 반드시 작은따옴표로 묶어야 하고, 문자열은 큰 따옴표로 묶어야 한다. 큰 따옴표로 묶은 문자열을 출력하려면 %s 서식지정자를 사용한다.

다음은 정수 리터럴의 표기 방법이다.

#include <stdio.h>

int main()
{
    printf("%d\n", 19);        // 10진 정수 리터럴
    printf("0%o\n", 017);      // 8진 정수 리터럴
    printf("0x%X\n", 0x1F);    // 16진 정수 리터럴

    return 0;
}

8진수는 서식지정자로 %o를 사용한다. 8진수는 앞에 0을 붙이고, 16진수는 앞에 0x를 붙여 10진수와 구분하기 쉽게 한다.

실수 리터럴 표기는 다음과 같다.

#include <stdio.h>

int main()
{
    printf("%f\n", 0.1F);       // 실수 리터럴 소수점 표기
    printf("%f\n", 1.0e-5f);    // 실수 리터럴 지수 표기법
}

실수 리터럴이 float 크기면 끝에 f를 붙이고, long double크기라면 끝에 l 또는 L을 붙인다. 지수표기법은 e 또는 E와 지수를 표기한다.

 

10.2 상수 사용하기

자료형 앞에 const를 붙이면 상수를 사용할 수 있다.

#include <stdio.h>

int main()
{
    const int con1 = 1;        
    const float con2 = 0.1f;   
    const char con3 = 'a';      

    printf("%d %f %c\n", con1, con2, con3);
    return 0;
}

상수는 반드시 선언과 동시에 초기화 해야 하며 초기화 하지 않으면 컴파일 에러를 발생한다. 상수도 변수처럼 이름으로 저장된 값을 출력할 수 있다.

#include <stdio.h>

int main()
{
    const int con1 = 1;
    con1 = 2; 
    printf("%d\n", con1);

    return 0;
}

위와 같이 상수에 값을 할당하면 이후에 값을 변경할 수 없다. const는 다음과 같이 자료형 뒤에 붙여도 된다.

int const con1 = 1;

 

10.3 정수 리터럴 접미사 사용하기

리터럴의 크기를 명확하게 하려면 접미사를 사용할 수 있다.

#include <stdio.h>

int main()
{
    printf("%ld\n", -10L);                       // long 크기의 정수 리터럴
    printf("%lld\n", -1234567890123456789LL);    // long long 크기의 정수 리터럴

    printf("%u\n", 10U);                         // unsigned int 크기의 정수 리터럴
    printf("%lu\n", 1234567890UL);               // unsigned long 크기의 정수 리터럴

    printf("%lu\n", 10UL);                       // unsigned long 크기의 정수 리터럴
    printf("%llu\n", 1234567890123456789ULL);    // unsigned long long 크기의 정수 리터럴

    return 0;
}

리터럴은 접미사를 사용하여 정수 자료형으로 크기를 정하는 것 처럼 리터럴의 크기를 명시적으로 표시할 수 있다. 정수 리터럴 접미사 목록은 다음과 같다.

접미사는 소문자와 대문자 모두 사용할 수 있고, u로 부호를, l로 크기를 표현한다.

다음과 같이 8진수와 16진수에서도 리터럴을 사용할 수 있다.

#include <stdio.h>

int main()
{
    printf("0%lo\n", 017L);           
    printf("0%lo\n", 017UL);            
    printf("0x%lX\n", 0x7FFFFFL);       
    printf("0x%lX\n", 0xFFFFFFFFUL);  

    return 0;
}

 

10.4 실수 리터럴 접미사 사용하기

#include <stdio.h>

int main()
{
    printf("%f\n", 0.1F);     // float 크기의 실수 리터럴
    printf("%f\n", 0.1);      // double 크기의 실수 리터럴
    printf("%Lf\n", 0.1L);    // long double 크기의 실수 리터럴

    printf("%f\n", 1.0e-5F);     // float 크기의 실수 리터럴
    printf("%f\n", 1.0e-5);      // double 크기의 실수 리터럴
    printf("%Lf\n", 1.0e-5l);    // long double 크기의 실수 리터럴

    return 0;
}

실수 리터럴 끝에 f를 붙이면 float크기가 되고, l을 붙이면 long double크기가 되고, 아무것도 붙이지 않으면 double크기가 된다. 대소문자는 구분하지 않는다.

 

10.5 퀴즈

정답은 d이다. 문자열은 큰따옴표로 감싸야 한다.

정답은 c이다.

정답은 e이다. ull은 unsigned long long 이다.

정답은 c이다. 접미사가 붙어있지 않으면 double이다.

 

10.6 연습문제 : 리터럴 사용하기

정답은 다음과 같다.

'e', "world!", 8, 4.9e-302L

 

10.7 연습문제 : 상수 사용하기

정답은 다음과 같다. 

  1. unsigned long long int con1 = 10ULL;
  2. float con2 = 3.2f
  3. char con3 = 't';

 

10.8 심사문제 : 리터럴 사용하기

정답은 다음과 같다.

076, -2147483647LL, 4.528172L

 

10.9 심사문제 : 상수 사용하기

정답은 다음과 같다.

long double con1 = -2.225074e-308

 

Unit 11. 입력값을 변수에 저장하기

C를 공부할 때는 콘솔에 글자를 입출력 하는데, 콘솔에 입력하는 방식을 표준 입력(standard input, stdin), 출력하는 방식을 표준 출력(standard output, stdout)이라고 한다.

 

11.1 정수 입력 받기

scanf 함수를 사용하여 표준 입력으로 사용자의 입력을 받아온다. scanf함수는 다음과 같이사용한다.

  • scanf(서식, 변수의주소);
    • int scanf(char const * const _Format, ...);
    • 성공하면 가져온 값의 개수를 반환, 실패하면 EOF(-1)를 반환

파이썬에서는 input함수로 입력받으면 모두 문자열 이였는데, C에서는 입력값을 저장할 변수를 미리 만들어 두고, 그 변수에 입력값을 저장하기 때문에 입력받을 값의 자료형이 정해져 있다. 

#define _CRT_SECURE_NO_WARNINGS    // scanf 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>

int main()
{
    int num1;

    printf("정수를 입력하세요 : ");
    scanf("%d", &num1);

    printf("%d\n", num1);
    return 0;
}

scanf함수의 첫번째 인수로는 큰따옴표 안에 서식지정자를 넣어 입력받을 값의 형태를 설정한다. 두번째 인수에는 입력값을 저장할 변수를 넣는데, 변수 앞에 &를 붙여야 한다. 맨 첫 줄은 윈도우 Visual studio에서 발생하는 에러를 방지하는 것으로 입력값의 길이를 설정할 수 없어서 보안에 취약하니 사용하지 말라는 경고가 출력될수 있으니 방지하는 것이다. 첫줄을 사용하지 않아도 에러가 발생하지 않으려면 visual studio전용 함수인 입력값 길이를 저장할 수 있는 함수인 scanf_s 함수가 있다.

 

11.2 한 번에 정수 두 개 입력받기

#define _CRT_SECURE_NO_WARNINGS    // scanf 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>

int main()
{
    int num1, num2;

    printf("정수를 입력하세요 : ");
    scanf("%d %d", &num1, &num2);

    printf("%d %d\n", num1, num2);
    return 0;
}

입력값 두개 이상을 받을 때는 입력값의 개수 만큼 서식지정자를 지정하고, 서식지정자 개수만큼 입력받을 변수를 넣어주면 된다. 입력 받을 때도 입력값은 공백(스페이스)로 구분한다.

 

11.3 실수 입력받기

#define _CRT_SECURE_NO_WARNINGS    // scanf 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>

int main()
{
    float num1;

    printf("실수를 입력하세요 : ");
    scanf("%f", &num1);

    printf("%f\n", num1);
    return 0;
}

실수를 입력받았기 때문에 1을 입력해도 1.0이 출력된다. 

실수를 입력받을 것이므로 변수를 float로 선언하고, 서식지정자를 %f를 사용한다. 

만약 double로 선언했으면 scanf의 서식지정자로는 %lf를 사용해야 하며, long double로 선언했으면 %Lf를 사용해야 한다.

입력받고자 하는 자료형에 맞게 변수를 선언하고, 변수에 맞는 서식지정자를 사용하면 된다.

 

11.4 문자 입력받기

#define _CRT_SECURE_NO_WARNINGS    // scanf 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>

int main()
{
    char c1;

    printf("문자를 입력하세요 : ");
    scanf("%c", &c1);

    printf("%c\n", c1);
    return 0;
}

문자를 입력받을 것이므로 변수는 char로 선언하고, 서식지정자도 %c를 사용하면 된다.

다음과 같이 getchar 함수를 이용해서 문자를 입력받을 수도 있다.

#include <stdio.h>

int main()
{
    char c1 = getchar();
    printf("%c\n", c1);
    return 0;
}

getchar 함수는 문자 하나를 입력받아 결과를 반환하는 함수이다. 문자를 여러개 입력받아도 첫번째 문자 하나만 반환된다.

이와 대응되는 함수로는 문자 하나를 화면에 출력하는 putchar함수가 있다.

#include <stdio.h>

int main()
{
    char c1 = getchar();
    putchar(c1);
    return 0;
}

 

11.5 퀴즈

정답은 b이다.

정답은 e이다.

정답은 c이다.

 

11.6 연습문제 : 한 번에 정수 세 개 입력받기

정답은 다음과 같다.

"%d %d %d", &num1, &num2, &num3

 

11.7 심사문제 : 정수, 실수, 문자 입력받기

정답은 다음 코드와 같다.

#define _CRT_SECURE_NO_WARNINGS   
#include <stdio.h>

int main()
{
    int n; 
    float f;
    char c;
    scanf("%d %f %c", &n, &f, &c);

    printf("%d\n%f\n%c\n", n, f, c);
    return 0;
}

 

Unit 12. 덧셈 뺄셈 하기

12.1 덧셈, 뺄셈 하기

덧셈은 +연산자, 뺄셈은 -연산자를 사용한다.

#include <stdio.h>

int main()
{
    int num1, num2;

    num1 = 1 + 1;
    num2 = 1 - 2;

    printf("%d\n", num1);
    printf("%d\n", num2);
    return 0;
}

num1 에 1+1을 저장하고, num2에 1-2를 저장하고 각 변수를 출력하면 각각의 연산결과가 나오는 것을 확인할 수 있다.

다음과 같이 실수에서도 덧셈, 뺄셈의 연산은 동일하다.

#include <stdio.h>

int main()
{
    float num1, num2;

    num1 = 1.0f + 0.112233f;
    num2 = 1.0f - 0.123456f;

    printf("%f\n", num1);
    printf("%f\n", num2);
    return 0;
}

 

12.2 변수 하나에서 값을 더하거나 빼기

다음과 같이 변수 하나에서 값을 더하거나 뺄 수 있다.

#include <stdio.h>

int main()
{
    int num1 = 1;
    int num2 = 1;

    num1 = num1 + 2;
    num2 = num2 - 2; 

    printf("%d\n", num1);  
    printf("%d\n", num2);    
    return 0;
}

num1에 기존 num1의 값에서 2를 더한 값을 저장하는 것이다. num1 + 2 가 처리되어 3이 된것이 num1에 다시 저장되는 것이다. 뺄셈의 경우도 동일하다.

C에서는 위 연산과 동일한 연산을 하는 덧셈후 할당 +=, 뺄셈후 할당 -= 연산자를 제공한다.

#include <stdio.h>

int main()
{
    int num1 = 1;
    int num2 = 1;

    num1 += 2;
    num2 -= 2;

    printf("%d\n", num1);  
    printf("%d\n", num2);    
    return 0;
}

num1 += 2 는 num1 = num1 + 2의 축약형이고, num2의 경우 뺄셈 연산도 마찬가지다.

 

12.3 퀴즈

정답은 b이다.

정답은 c이다.

정답은 d이다.

 

12.4 연습문제 : 덧셈, 뺄셈 하기

num1의 값은 현재 5이므로 답은 95이다.

 

12.5 : 심사문제 : 덧셈, 뺄셈하기

출력하는 값이 num3이므로 연산한 값은 num3에 저장해야 한다.

num3 = num1 + num2 - 4.5f;

 

Unit 13. 증가, 감소 연산자 사용하기

C에서는 값을 1 증가시키는 ++연산자와 값을 1 감소시키는 -- 연산자를 제공한다. 정수에서는 1을 증가와 감소 시키지만, 포인터 연산을 하게 되면 자료형의 크기만큼 증가, 감소 시킨다.

 

13.1 변수의 값을 1 증가, 감소 시키기

증가연산은 ++연산자를 사용하고, 감소연산은 --연산자를 사용하며 값을 1 증가시키거나 감소시킨다. 증가, 감소 연산자는 다음과 같이 변수의 앞이나 뒤에 붙일 수 있다.

#include <stdio.h>

int main()
{
    int num1 = 1, num2 = 1;

    num1++;
    --num2;

    printf("num1 : %d\n", num1);
    printf("num2 : %d\n", num2);
    return 0;
}

num1++ 를 풀어서 쓰면 num1 = num1 + 1과 같고, num1+=1 과도 동일하다. 감소 연산자도 마찬가지다.

 

13.2 실수 자료형에 증감 연산자 사용하기

실수자리에 증감 연산자를 사용하면 다음과 같다.

#include <stdio.h>

int main()
{
    float num1 = 2.1f;
    float num2 = 2.1f;

    num1++;    
    num2--;

    printf("%f %f\n", num1, num2); 
    return 0;
}

실수에서도 증감연산자를 사용하여 1 증가시키거나 감소시킬수 있다. 증감연산자는 정수 부분에만 영향을 미치며, 소수점 이하 자리에는 영향을 미치지 않는다.

 

13.3 문자 자료형에 증감 연산자 사용하기

문자 자료형에 증감 연산자를 사용하면 다음과 같다.

#include <stdio.h>

int main()
{
    char c1 = 'b';
    char c2 = 'b';

    c1++;   
    c2--;    

    printf("%c %c\n", c1, c2);  
    return 0;
}

문자 자료형도 실제로는 정수이기 때문에 아스키 코드값이 1 증가하거나 감소하여 b에서 1을 증가시키면 c가되고, 1을 감소시키면 a가 된다.

파이썬에서는 문자 자료형에 숫자를 연산하면 에러가 발생한다.

 

13.4 증감 연산자의 위치에 따른 차이점 알아보기

증감 연산자는 변수 앞이나 뒤에 사용할 수 있다. 이는 증감연산자 단독으로 사용했을때는 차이가 없지만, 연산자를 사용한 뒤 다른 변수에 할당할 때 위치에 따라 차이가 발생한다.

다음은 증감연산자를 변수 뒤에 사용했을 경우이다.

#include <stdio.h>

int main()
{
    int num1 = 2;
    int num2 = 2;
    int num3;
    int num4;

    num3 = num1++; 
    num4 = num2--; 

    printf("%d %d\n", num3, num4);  
    return 0;
}

num3과 num4에 처음 num1과 num2에 저장한 2가 저장되어 있다. 위 연산을 풀어서 쓰면 다음과 같다.

num3 = num1;
num1 = num1 + 1;

num4 = num2;
num2 = num2 - 1;

이와 같이 증감 연산자를 변수 뒤에 사용하는 것을 후위 연산이라고 하며 다른 변수에 할당할 때는 현재 변수의 값을 다른 변수에 할당한 후 증감연산자가 수행되어 변수의 값이 1 증가, 감소 된다. 따라서 num3과 num4에는 num1과 num2의 처음 값인 2가 저장되고 이후 증감 연산이 수행되어 num1과 num2에는 각각 3과 1이 저장되어 있을 것이다.

증감 연산자를 변수 앞에 사용하면 다음과 같다.

#include <stdio.h>

int main()
{
    int num1 = 2;
    int num2 = 2;
    int num3;
    int num4;

    num3 = ++num1; 
    num4 = --num2; 

    printf("%d %d\n", num3, num4);  
    return 0;
}

위 연산을 풀어서 작성하면 다음과 같다.

num1 = num1 + 1;
num3 = num1;

num2 = num2 - 1;
num4 = num2;

증감 연산자를 변수 앞에 사용한 것을 전위 연산이라고 한다. 전위 연산은 할당 전에 연산을 하여 연산한 값을 변수에 할당한다. num1 + 1을 한 값이 num3에 저장되어 3이 출력되는 것이다. 감소 연산도 동일하다.

변수에 할당하지 않고 함수의 인수로 사용했을 때도 동작 방식은 같다.

#include <stdio.h>

int main()
{
    int num1 = 2;
    int num2 = 2;

    printf("%d %d\n", num1++, num2--); 
    printf("%d %d\n", num1, num2);     

    return 0;
}

#include <stdio.h>

int main()
{
    int num1 = 2;
    int num2 = 2;

    printf("%d %d\n", ++num1, --num2); 
    printf("%d %d\n", num1, num2);     

    return 0;
}

변수 뒤에 증감연산자를 사용하면(후위 연산) 기존 값이 먼저 출력되고 이후 증감 연산을 진행한다. 또한 변수 앞에 증감연산자를 사용하면(전위 연산) 연산을 먼저 하고, 연산한 값을 출력한다.

 

13.5 퀴즈

정답은 d이다.

정답은 c이다.

정답은 e이다.

후위 연산 이기 때문에 정답은 12 이다.

전위연산이기 때문에 정답은 8이다.

 

13.6 연습문제 : 증가, 감소 연산자 사용하기

num3은 num1의 처음 값에서 1증가시키고, 1감소시킨 것이기 때문에 첫번째 답은 2이고, num4는 num2의 처음값을 1 감소시키고 그 값을 후위연산한 것을 저장했기 때문에 두번째 답은 8 이다.


13.7 심사문제 : 증가, 감소 연산자 사용하기

정답은 다음 코드와 같다.

num1++;
num2++;
c1--;

 

Unit 14. 곱셈, 나눗셈 하기

14.1 곱셈, 나눗셈 하기

곱셈은 *연산자, 나눗셈은 / 연산자를 사용한다.

#include <stdio.h>

int main()
{
    int num1;
    int num2;

    num1 = 2 * 3;  
    num2 = 7 / 2;   

    printf("%d\n", num1);  
    printf("%d\n", num2);    
    return 0;
}

곱셈은 특별한 것이 없지만, 나눗셈은 정수끼리 나눗셈을 하면 결과가 정수로 나오기 때문에 3.5가 아니라 3만 나온다. 

파이썬에서는 정수끼리 나눠도 값이 소수라면 소수를 반환하여 몫만 구하는 연산자가 따로 있었지만, C에서는 정수끼리 나누면 정수인 몫만 나온다.

또한 컴퓨터에서 정수는 0으로 나눌수 없다. 0으로 나누려고 하면 컴파일 에러가 발생하고, 변수에 다른 숫자와 0을 각각 저장해서 나누면 컴파일 에러는 발생하지 않지만 실행했을 때 에러를 발생한다.

다음은 실수를 계산한 것이다.

#include <stdio.h>

int main()
{
    float num1;
    float num2;

    num1 = 2.73f * 3.81f;
    num2 = 7.0f / 2.0f;      

    printf("%f\n", num1);   
    printf("%f\n", num2);
    return 0;
}

실수끼리 나눗셈을 하면 소숫점도 계산된다.

곱셈의 경우 2.73 에 3.81을 곱하면 10.4013이 나와야 하는데, 10.401299가 나온다. 실수의 계산은 경우에 따라 오차가 발생하기도 한다. 곱셈 뿐아니라 덧셈, 뺄셈, 나눗셈 등에서도 발생할 수 있다.

실수도 코드에서 0으로 직접 나누면 컴파일 에러가 발생한다.

다음과 같이 변수에 0.0을 저장하여 나누면 정수처럼 실행했을 때 에러가 발생하지 않고, inf(무한대)가 나온다.

#include <stdio.h>

int main()
{
    float num1 = 1.0f;
    float num2 = 0.0f;
    float num3;

    num3 = num1 / num2;

    printf("%f\n", num3);   
    return 0;
}

 

14.2 변수 하나에서 값을 곱하거나 나누기

#include <stdio.h>

int main()
{
    int num1 = 2;
    int num2 = 7;

    num1 = num1 * 3; 
    num2 = num2 / 2;    

    printf("%d\n", num1);   
    printf("%d\n", num2);    
    return 0;
}

위 코드는 변수의 값을 곱하거나 나눈뒤 다시 그 변수에 저장하여 계산 결과를 같은 변수에 유지시킨 것이다.

곱셈후 할당 *=, 나눗셈 후 할당 /= 연산자를 사용하여 위 코드의 연산을 다음과 같이 축약할 수 있다.

num1 *= 3;
num2 /= 2;  

 

14.3 퀴즈 

정답은 a 이다.

정답은 c이다. 0으로 나누면 컴파일 에러가 발생한다.

정답은 c이다.

 

14.4 연습문제 : 삼각형의 넓이 구하기

삼각형의 넓이는 밑변 * 높이 / 2 이므로 정답은 다음과 같다.

base * height / 2

 

14.5 : 심사문제 : 원의 넓이 구하기

원의 넓이는 반지름 * 반지름 * 원주율 이므로 정답은 다음 코드와 같다.

radius = diameter / 2;
area = radius * radius * M_PI;

 

Unit 1. 소프트웨어 교육과 C언어

컴퓨터 과학이 사용되는 범위가 애니메이션, 의학, 패션, 기계공학까지 점점 늘어나고 있고 프로그래밍 활용 분야도 마케팅등 점점 넓어지고 있다. 프로그래밍으로 문제를 해결할 수 있는 부분이 있다면 어느 분야에서든 활용할 수 있다.

 

1.1 컴퓨터와 프로그램 

프로그램은 사람이 원하는 작업을 처리해주는 도구이다. 그러나 기존에 있는 도구로는 원하는 작업을 처리할 수 없을 때 프로그래밍을 통해 직접 문제를 해결하는 프로그램을 만들 수 있다.

 

1.2 문제 해결을 위한 과학적 사고

복잡한 문제 하나를 해결하기 위해서는 복잡한 문제를 작은 문제들로 작은 문제들을 하나씩 접근하여 해결한다. 다음과 같이 사진을 특수문자로 변환하는 것을 아스키 아트라 한다.

사진을 아스키 아트로 변환하는 것을 작은 문제로 나누어 보면 이미지의 각 픽셀에 대한 정보를 얻어오고, 픽셀의 색상 정보를 얻어오고, 그에 맞는 특수 문자로 출력하는 작은 문제로 나눌 수 있다. 이것처럼 현실 세계의 문제를 분석하여 해결책을 찾는 과학적 사고법을 컴퓨테이셔널 씽킹 이라 하고, 이렇게 설계한 해결책을 컴퓨터 명령어로 작성하는 것을 컴퓨터 프로그래밍이라 한다.

작은 문제로 분해하고, 문제의 패턴을 발견하고, 어떤 데이터를 이용할지 결정하고, 문제를 일반화하고 모델링할 수 있는지를 찾는 과정이다.

아스키 아트로 변환하는 과정을 패턴, 데이터, 일반화와 모델링 과정으로 분류하면 다음과 같다.

  • 패턴: 이미지 파일을 읽어서 픽셀의 색상에 따라 특수 문자로 출력
  • 데이터: 이미지 파일의 픽셀 데이터, 특수 문자
  • 일반화와 모델링: 이미지 파일 읽기, 이미지 파일 분석

 

1.3 알고리즘과 코딩

파이썬 코딩도장에서 정리한 내용과 동일하다.

studyit312.tistory.com/152?category=454681

 

[Project H4C] 파이썬 코딩도장(1)

Unit 1. 소프트웨어 교육과 파이썬 1.1 문제 해결을 위한 과학적 사고 전화기, 자동차, 영화산업, 의료 기술, 인공지능 등의 발달로 소프트웨어의 사용 범위는 계속 넓어지고 있다. 그 결과 소프트

studyit312.tistory.com

 

1.4 C 언어란?

1972년 켄 톰슨과 데니스 리치가 유닉스 운영체제를 만들기 위해 고안한 프로그래밍 언어이다. 

켄 톰슨이 BCPL언어를 고쳐 B언어를 개발하였고, 데니스 리치가 B언어를 개선하여 C언어를 개발했다. C언어는 이후의 프로그래밍 언어에 직간접적으로 많은 영향을 주었다.

윈도우, 리눅스, osX등 운영체제의 핵심 요소인 커널도 C언어로 만들어져 있다. 

C는 데이터베이스, 가전제품의 컴퓨터, IoT를 만드는데도 사용된다.

메모리와 하드웨어를 직접 제어할 수 있는 언어 이기도 하다.

 

1.5 코딩도장을 학습하는 방법

파이썬 코딩도장을 통해 학습하는 방법을 알고 있기에 생략한다.

 

Unit 2. Visual Studio 설치하기

컴파일러로 visual studio code를 사용할 것이고, 설치되어 있기에 생략한다.

 

Unit 3. Hello, world!로 시작하기

3.1 새 프로젝트 만들기

3.2 프로젝트에 C언어 소스파일 추가하기

다음과 같이 작업공간으로 사용할 폴더를 만들어 hello.c 소스파일을 만들었다.

 

3.3 Hello, world! 출력하기

소스 파일에 다음과 같이 입력한다.

#include <stdio.h>

int main()
{
    printf("Hello world!\n");
    
    return 0;
}

Ctrl + F5 키를 누르면 소스파일을 컴파일 하여 실행 파일을 만들 수 있다. 또한 vscode에서 code runner 확장 프로그램을 이용하면 우측 상단의 재생 버튼을 눌러 바로 컴파일 하여 실행할 수 있다.

다음과 같이 터미널에서도 실행 파일을 실행할 수 있다.

위의 소스코드를 보면 printf가 Hello, world!를 출력한다. " "(큰따옴표)로 감싼 부분을 문자열이라 하고, printf()는 화면에 문자열을 출력하는 함수이다. main, printf등 뒤에 괄호가 붙은 단어를 함수라 한다.

printf()괄호 뒤에 ;(세미클론)을 붙이면 printf함수가 실행된다. 함수가 실행되는 것을 함수를 호출(call)한다고 하기도 한다.

Hello, world! 뒤에 붙은 \n은 출력되지 않는다. \n은 제어문자로 화면에 직접 표시되지 않고 문자열을 다음 줄에서 출력되도록 하는 엔터키와 같은 역할을 한다. 파이썬의 print함수는 실행하고 줄바꿈을 하는 것이 기본 설정이라 줄바꿈이 필요 없을 때 따로 지정했어야 했는데 C의 printf함수는 실행하고 줄바꿈을 하지 않아서 줄바꿈을 원하면 \n 제어문자를 넣어야 한다.

소스 코드의 첫줄에 있는 #include는 헤더파일을 포함하는 문법이다. printf 함수를 사용하려면 stdio.h 헤더 파일이 필요하다. 

파이썬에서는 소스 파일에 바로 작성하면 됬지만, C의 경우 사용하려는 함수마다 그 함수를 포함하고 있는 헤더파일을 모두 지정해 줘야 한다.

main() 함수는 C로 프로그램을 만들었을 때 프로그램에서 가장 먼저 실행되는 함수이다. 소스에서 main함수가 없다면 컴파일 되지 않기 때문에 main함수는 반드시 있어야 한다. 

main 함수의 마지막에 return 0; 이 있다. 함수는 반환값을 함수 바깥으로 전달할 수 있다. main함수도 함수이기 때문에 반환 값을 반환할 수 있다.

 

3.4 서식지정자 사용하기

서식 지정자는 printf로 문자열을 출력할 때 값으로 바뀌는 부분이다.

#include <stdio.h>

int main()
{
    printf("%s\n", "Hello, world!");
    
    return 0;
}

printf함수에 %s를 사용하고 "Hello, world!"를 넣어주면 %s 부분이 "Hello, world!"로 바뀌게 된다. 

서식 지정자는 변수를 사용하여 같은 내용을 여러 개 출력하거나, 출력 형태를 바꿀 때 유용하게 사용할 수 있다. 다음과 같이 %s를 여러 번 사용하면 각 %s에 들어갈 문자열을 ,(콤마)로 구분하여 넣으면 된다. 

printf("%s %s\n", "Hello", "123");

서식지정자 사이에는 공백이나 여러 문자들이 들어가 서식지정자의 내용과 출력할 문자열을 조합하여 최종 결과를 만들어 낸다.

printf("%s%s\n", "Hello", "123");
printf("%s w%s\n", "Hello", "orld!");

 

3.5 심사 사이트 이용하기

파이썬 코딩도장을 진행하며 사용해봤기에 생략한다.

 

3.6 퀴즈

정답은 b이다.

정답은 d이다.

정답은 main이다.

 

3.7 연습문제: 문자열 출력하기

정답은 다음과 같다.

  1. "Hello, world!\n"
  2. "1234567890\n"

 

3.8 연습문제 : 서식지정자 사용하기

서식지정자 앞에 Hello, 가 있기 때문에 정답은 "world!"이다.

 

3.9 심사문제 : 문자열 출력하기

제어문자 \n을 이용하여 줄바꿈을 할 수 있으므로 정답은 다음 코드와 같다.

printf("Hello, world!\nHello, world!\n");

 

3.10 심사문제 : 서식 지정자 사용하기

서식 지정자가 3개 있고, 콤마와 공백이 출력하는 문자열이 있으므로 각 서식문자에는 "Hello", "C", "Language"가 들어가면 된다.

 

Unit 4. 기본 문법 알아보기

4.1 세미클론

C언어는 구문이 끝날 때 ;(세미클론)을 붙인다. if나 for문등 여러줄로 내용이 계속 이어지는 문법은 세미클론을 붙이지 않는다.

파이썬에서는 구문이 끝나도 세미클론을 붙이지 않아도 됬지만, C언어의 경우 세미클론을 붙이지 않으면 컴파일에러가 발생한다.

 

4.2 주석

사람만 알아볼 수 있도록 작성하는 부분을 주석이라 한다. 주석은 코드에 대한 자세한 설명을 작성하거나, 특정 코드를 임시로 컴파일 되지 않게 만들 때 사용한다. 파이썬에서 사용한 #을 이용한 주석과 동일한 역할이다.

한줄 주석은 다음과 같이 //을 사용한다. // 뒤에 있는 내용은 코드로 실행되지 않는다.

// 문자열 출력
printf("hello\n");	// hello 출력
// printf("hello world\n");

범위 주석은 다음과 같이 /* 로 시작하며 */ 여러줄을 주석으로 만들 때 사용하며 한줄에서 부분만 주석으로 만들 수 있다.

/*
printf("Hello, world!\n");
printf("1234567890");
*/
printf("Hello" /* 안녕하세요 */);

 

4.3 중괄호 

C에서 중괄호는 코드의 범위를 나타낸다. 다음 코드의 경우 중괄호로 묶인 부분은 main 함수에 소속된 코드이다.

int main()
{
    printf("Hello, world!\n");

    return 0;
}

중괄호는 다음과 같이 if문이나 for문 등의 키워드가 영향을 미치는 영역을 묶을 때도 사용한다.

if (a > 10)
{
    printf("a");
}

for (int i = 0; i < 10; i++)
{
    printf("Hello, world!\n");
}

또한 다음과 같이 구조체(공용체, 열거형)를 정의할 때도 사용한다.

struct Hello {
    int a;
    int b;
};

중괄호 뒤에는 문법에 따라 세미클론을 붙일 때도 있고, 안붙일 때도 있다.

 

4.4 들여쓰기 

C에서는 키워드에 따라 들여쓰기를 사용한다. 보통 {(여는 중괄호)가 시작될 때 들여쓰기를 한다. 

다음과 같이 코드가 한 줄이라 중괄호를 생략할 때도 들여쓰기는 하는 것이 코드를 쉽게 알아보기에 좋다. 

들여쓰기 방법은 공백 두칸, 4칸, 탭 등 여러 방법이 있다.

들여쓰기 방법은 여러개지만, 다른 사람이 만든 소스코드를 수정할때는 기존의 들여쓰기 규칙을 따르는 것이 좋다.

 

Unit 5. 변수 만들기

변수는 자료형 뒤에 변수 이름을 선언하는 방식으로 만들 수 있다. 정수를 저장하는 변수를 만드려면 다음과 같이 선언한다.

int num1;

int 는 정수를 뜻하는 integer의 축약형이며 변수 이름은 다음의 규칙을 따르고, 원하는 대로 지으면 된다.

  • 영문 문자와 숫자를 사용할 수 있습니다.
  • 대소문자를 구분합니다.
  • 문자부터 시작해야 하며 숫자부터 시작하면 안 됩니다.
  • _ (밑줄 문자)로 시작할 수 있습니다.
  • C 언어의 키워드(int, short, long, float, void, if, for, while, switch 등)는 사용할 수 없습니다.

변수를 선언하고 맨 뒤에는 반드시 세미클론(;)을 붙여야 한다.

C언어는 파이썬과 달리 변수에 저장할 값에 따라 맞는 자료형을 지정해줘야 한다. C에서 사용할 수 있는 자료형의 종류는 다음과 같다.

  • char, short, int, long: 정수(저장할 수 있는 크기가 다릅니다)
  • float, double: 실수
  • void: 형태가 없는 자료형(포인터를 사용할 때, 함수의 반환값을 표현할 때 등 다양하게 사용됩니다)

 

5.1 변수를 만들고 값 저장하기

#include <stdio.h>

int main()
{
    int num1;   // 정수형 변수 선언
    int num2;
    int num3;

    num1 = 10;  // 변수에 값 할당
    num2 = 20;
    num3 = 30;

    printf("%d %d %d\n", num1, num2, num3);   // 변수에 저장한 값을 %d 로 출력
    return 0;
}

변수에 값을 할당(저장)할 때는 =(등호)를 사용한다. 변수에 값을 할당하고 출력할 때는 %d 서식지정자를 사용한다. %d는 10진수를 출력할 때 사용하는 서식지정자 이다. 서식지정자 %d에 각 변수가 대응되어 3개의 변수에 저장된 3개의 값이 출력되었다.

 

5.2 변수 여러 개를 한 번에 선언하기

#include <stdio.h>

int main()
{
    int num1, num2, num3;   // 변수를 콤마로 구분하여 여러개를 선언

    num1 = 10;  // 변수에 값 할당
    num2 = 20;
    num3 = 30;

    printf("%d %d %d\n", num1, num2, num3);   // 변수에 저장한 값을 %d 로 출력
    return 0;
}

위 코드와 같이 int를 한 번만 사용한 뒤 변수를 콤마로 구분하여 여러개의 변수를 선언할 수 있다. 자료형이 같을 때만 가능하며, 자료형이 다르다면 따로 선언해야 한다.

 

5.3 변수를 선언하면서 초기화하기

#include <stdio.h>

int main()
{
    int num1 = 10;  // 변수를 선언하면서 값 할당(초기화)
    int num2 = 20, num3 =30;    // 변수 여러 개를 선언하면서 값 할당(초기화)

    printf("%d %d %d\n", num1, num2, num3);   // 변수에 저장한 값을 %d 로 출력
    return 0;
}

위 코드처럼 변수를 선언하면서 =로 값을 할당하여 초기화 할 수 있다. 또한 변수 여러개를 선언하면서 값을 초기화 할 수 도 있다. 각 코드의 마지막에는 반드시 세미클론을 붙여야 한다.

 

5.4 퀴즈

정답은 c이다.

정답은 c, e, f, h 이다.

정답은 d이다.

정답은 b이다.

 

5.5 연습문제 : 변수 여러 개를 선언하면서 값 초기화 하기

변수 이름 num1, num2, num3 각각에 값 10, 20, 30을 할당해야 하므로 정답은 다음 코드와 같다.

int num1 = 10, num2 = 20, num3 = 30;

 

5.6 심사문제 : 변수를 선언하고 값 할당하기

num1 변수는 선언되어 있기 때문에 정답은 다음 코드와 같다.

num1 = 10;
int num2 = 20, num3 = 30;


Unit 6. 디버거 사용하기

버그는 프로그램이 의도치 않은 동작을 일으키는 것을 말한다. 디버거는 버그를 제거하는 도구 라는 뜻으로 프로그램의 내부 상황을 쉽게 파악할 수 있어 버그(문제점)를 찾는데 도움을 준다.

 

6.1 중단점 사용하기

중단점은 브레이크 포인트(Break point)라고도 부르는데, 소스코드의 특정 지점에서 프로그램의 실행을 멈추는데 사용한다. 소스코드는 다음 코드를 사용한다.

#include <stdio.h>

int main()
{
    int num1 = 10;  // 변수를 선언하면서 값 할당(초기화)
    int num2 = 20, num3 =30;    // 변수 여러 개를 선언하면서 값 할당(초기화)

    printf("%d %d %d\n", num1, num2, num3);   // 변수에 저장한 값을 %d 로 출력
    printf("%d\n", num2);
    return 0;
}

{ (여는 중괄호)가 있는 줄의 줄 번호 왼쪽을 클릭하면 빨간 원이 생긴다.

빨간색 원은 중단점을 의미하며 이곳에서 실행을 멈추라는 의미이다. 

중단점을 삽입하고, F5 키를 눌러서 디버깅을 시작한다.

그러면 노란색 화살표에 빨간 원이 들어가며 그 줄에서 프로그램이 중단된다. 

4번째 줄까지 실행 했고 5번째 줄을 실행할 차례라는 의미이다. 코드를 한줄 한줄 실행할 때는 F10 키를 누르면 된다. F10을 누르면 노란색이 한 줄씩 내려가면서 코드가 한줄 한줄 실행된다.

지금 상태는 num1, num2, num3 변수가 선언되며 값이 할당되고, 아직 출력은 하지 않은 상태이다. 지금 상태에서 DEBUG CONSOLE을 확인해보면 아무것도 출력되지 않는다.

여기서 F10을 한번 더 누르면 8번째 줄이 실행되여 3개의 변수가 출력된다.

한번 더 F10을 누르면 다음줄도 실행된다.

디버깅을 끝내려면 Shift + F5를 누르면 된다.

Visual Studio Code의 디버거 단축키는 다음과 같다.

  • 중단점 삽입/삭제: F9
  • 디버깅 시작: F5
  • 디버깅 중지: Shift+F5
  • 프로시저 단위 실행: F10
  • 한 단계씩 코드 실행: F11
    • 함수 안으로 들어갈 때 사용하는 단축키이다.

 

Unit 7. 정수 자료형 사용하기

정수 자료형은 크게 char과 int가 있고, 앞에 부호 키워드(signed, unsigned)와 크기 키워드(short, long)을 붙여서 특성을 정의할 수 있다.

signed는 부호가 있는 정수를 표현하며 보통 생략한다. unsigned는 부호가 없는 정수를 표현하여 값은 0부터 시작한다. 

C에서는 정수 자료형이 char ,int에 여러 키워드를 조합하여 여러가지가 있지만, 파이썬의 정수 자료형은 int 하나이다.

다음은 정수 자료형 키워드를 조합했을 때 자료형의 크기와 저장할 수 있는 값의 범위이다.

정수 자료형의 크기와 범위를 그림으로 표현하면 다음과 같다. signed와 unsigned는 범위가 다를 뿐 크기는 같다.

 

7.1 정수형 변수 선언하기

#include <stdio.h>

int main()
{
    char num1 = -10;    // 1바이트 부호 있는 정수
    short num2 = 30000; // 2바이트 부호 있는 정수
    int num3 = -1234567890; // 4바이트 부호 있는 정수
    long num4 = 1234567890; // 4바이트 부호 있는 정수
    long long num5 = -1234567890123456789; // 8바이트 부호 있는 정수

    printf("%d %d %d %ld %lld\n", num1, num2, num3, num4, num5);
    return 0;
}

위 코드는 부호있는 정수를 만들어 값을 할당한 것이다. 부호있는 정수는 보통 signed를 생략한다. short 와 long은 int 를 생략한다. char은 character의 약어로 문자를 뜻하지만 기본적으로는 정수형이다.

printf함수에서 char, short, int는 %d 서식지정자를 사용하지만 long는 %ld, long long는 %lld 서식지정자를 사용한다.

부호 없는 정수 자료형은 다음과 같다.

#include <stdio.h>

int main()
{
    unsigned char num1 = 200;   // 1바이트 부호 없는 정수
    unsigned short num2 = 60000;    // 2바이트 부호 없는 정수
    unsigned int num3 = 4123456789; // 4바이트 부호 없는 정수
    unsigned long num4 = 4123456789;    // 4바이트 부호 없는 정수
    unsigned long long num5 = 12345678901234567890; // 8바이트 부호 없는 정수

    printf("%u %u %u %lu %llu\n", num1, num2, num3, num4, num5);
    return 0;
}

부호 없는 정수 자료형은 앞에 unsigned 키워드를 붙여주면 된다. 

printf함수에서 서식지정자로 %d를 사용해도 되지만, unsigned키워드가 붙은 정수는 %u, %lu, %llu를 이용하여 출력해야 한다.

 

7.2 오버플로우와 언더플로우 알아보기

#include <stdio.h>

int main()
{
    char num1 = 128;
    unsigned char num2 = 256;

    printf("%d %u\n", num1, num2);
    return 0;
}

num1 은 char 자료형 범위의 최대값인 127 보다 큰 128을 저장했고, num2는 unsigned char 자료형 범위의 최대값인 255보다 큰 256을 저장했다. 실제 출력에서는 -128과 0이 나왔다. 저장할 수 있는 최대값의 범위를 넘어서서 오버플로우가 발생하여 다시 최솟값부터 시작하게 되므로 -128과 0이 나오는 것이다. 다른 자료형들도 저장할 수 있는 최대값의 범위를 넘어서면 오버플로우가 발생해 최솟값부터 다시 시작한다.

반대로 저장할 수 있는 최솟값보다 작은 값을 저장하면 언더플로우가 발생하여 최댓값에서 다시 시작하게 된다.

파이썬에서는 int 자료형이 숫자의 범위를 제한하고 있지 않아서 오버플로우가 발생하지 않을 것이다.

 

7.3 자료형 크기 구하기

자료형의 크기를 바이트 단위로 구할 때는 sizeof 연산자를 사용한다. sizeof 연산자는 다음과 같은 형식으로 사용한다.

  • sizeof 표현식
  • sizeof(자료형)
  • sizeof(표현식)
#include <stdio.h>

int main()
{
    int num1 = 0;
    int size;

    size = sizeof num1;
    
    printf("num1의 크기 : %d\n", size);
    return 0;
}

변수 num1의 자료형 크기를 구한 것이다. 표현식은 변수, 상수, 배열 등 프로그래머가 만들어낸 요소를 뜻한다. 정수 int형 변수 num1의 자료형을 구했기 때문에 4가 출력됬다.

다음과 같이 sizeof(자료형)의 방식과 sizeof(표현식)의 방식으로도 사용할 수 있다.

int size1;
int size2;
int num1 = 0;

size1 = sizeof(int);
size2 = sizeof(num1);

각 정수 자료형의 크기를 구해보면 다음과 같다.

#include <stdio.h>

int main()
{
    printf("char : %d, short : %d, int : %d, long : %d, long long : %d\n",
        sizeof(char),
        sizeof(short),
        sizeof(int),
        sizeof(long),
        sizeof(long long)
    );

    return 0;
}

char는 1바이트, short는 2바이트, int long은 4바이트, long long은 8바이트이다.

 

7.4 최솟값과 최댓값 표현하기

소스코드에서 정수의 최솟값을 표현하려면 limits.h 헤더 파일을 사용해야 한다. limits.h는 자료형의 최솟값과 최댓값이 정의된 헤더파일이다.

#include <stdio.h>
#include <limits.h>

int main()
{
    char num1 = CHAR_MIN;       // char 최솟값
    short num2 = SHRT_MIN;      // short 최솟값
    int num3 = INT_MIN;         // int 최솟값
    long num4 = LONG_MIN;       // long 최솟값
    long long num5 = LLONG_MIN; // long long 최솟값

    printf("%d %d %d %ld %lld\n", num1, num2, num3, num4, num5);
    return 0;
}

limits.h 파일에는 다음과 같이 정수 자료형들의 최솟값과 최댓값이 정의되어 있다.

다음과 같이 limits.h에 정의된 최댓값을 넘어서도 오버플로우가 발생하여 최솟값부터 다시 시작하며, 최솟값보다 작아지면 언더플로우가 발생하여 최댓값이 출력되게 된다.

#include <stdio.h>
#include <limits.h>

int main()
{   
    // 부호 있는 정수 오버플로우
    char num1 = CHAR_MAX + 1;
    short num2 = SHRT_MAX + 1;
    int num3 = INT_MAX + 1;
    long long num4 = LLONG_MAX + 1;
    printf("%d %d %d %lld\n", num1, num2, num3, num4);

    // 부호 없는 정수 오버플로우
    unsigned char num5 = UCHAR_MAX + 1;
    unsigned short num6 = USHRT_MAX + 1;
    unsigned int num7 = UINT_MAX + 1;
    unsigned long long num8 = ULLONG_MAX +1;
    printf("%u %u %u %llu\n", num5, num6, num7, num8);

    // 부호 있는 정수 언더플로우
    char num9 = CHAR_MIN - 1;
    short num10 = SHRT_MIN - 1;
    int num11 = INT_MIN - 1;
    long long num12 = LLONG_MIN - 1;
    printf("%d %d %d %lld\n", num9, num10, num11, num12);

    // 부호 없는 정수 언더플로우
    unsigned char num13 = 0 - 1;
    unsigned short num14 = 0 - 1;
    unsigned int num15 = 0 - 1;
    unsigned long long num16 = 0 - 1;
    printf("%u %u %u %llu\n", num13, num14, num15, num16);

    return 0;
}

값을 계산하다가 오버플로우 또는 언더플로우 현상이 발생할 경우 의도치 않은 결과가 나올 수 있기 때문에 프로그래밍 할 때는 값의 범위를 항상 주의해야 한다.

 

7.5 크기가 표시된 정수 자료형 사용하기

C99 표준부터 stdint.h 헤더 파일이 추가되면서 크기가 표시된 정수 자료형을 사용할 수 있게 되었다.

#include <stdio.h>
#include <stdint.h>

int main()
{
    int8_t num1 = -128;                    // 8비트(1바이트) 크기의 부호 있는 정수
    int16_t num2 = 32767;                  // 16비트(2바이트) 크기의 부호 있는 정수
    int32_t num3 = 2147483647;             // 32비트(4바이트) 크기의 부호 있는 정수
    int64_t num4 = 9223372036854775807;    // 64비트(8바이트) 크기의 부호 있는 정수

    printf("%d %d %d %lld\n", num1, num2, num3, num4);

    uint8_t num5 = 255;                      // 8비트(1바이트) 크기의 부호 없는 정수
    uint16_t num6 = 65535;                   // 16비트(2바이트) 크기의 부호 없는 정수
    uint32_t num7 = 4294967295;              // 32비트(4바이트) 크기의 부호 없는 정수
    uint64_t num8 = 18446744073709551615;    // 64비트(8바이트) 크기의 부호 없는 정수

    printf("%u %u %u %llu\n", num5, num6, num7, num8); 
    return 0;
}

출력할 때는 int64_t와 uint64_t만 %lld와 %llu로 출력하고 나머지는 %d와 %u로 출력한다.

stdint의 최소 최댓값은 헤더 파일 안에 정의 되어 있어 limits.h헤더파일을 따로 사용하지 않아도 된다.

  • 부호 있는 정수(signed) 최솟값: INT8_MIN, INT16_MIN, INT32_MIN, INT64_MIN
  • 부호 있는 정수 최댓값: INT8_MAX, INT16_MAX, INT32_MAX, INT64_MAX
  • 부호 없는 정수(unsigned) 최솟값: 0
  • 부호 없는 정수 최댓값: UINT8_MAX, UINT16_MAX, UINT32_MAX, UINT64_MAX

 

7.6 퀴즈

정답은 c이다. int는 4바이트이다.

정답은 d이다. unsigned 자료형의 최솟값은 0이다.

정답은 b이다.

정답은 e이다. 자료형으로 크기를 구하려면 괄호에 넣어야 한다.

정답은 c이다.

정답은 e이다.

 

7.7 연습문제 : 정수형 변수 선언과 오버플로우

정답은 다음 코드와 같다.

unsigned char
unsigned short
long long

 

7.8 연습문제 : 자료형 크기 구하기

sizeof(int)는 4이기 때문에 sizeof(num1)과 sizeof(num2)의 합은 10이 되어야 하므로 정답은 다음과 같다.

short
long long

 

7.9 연습문제 : 최댓값 표현하기

정답은 다음과 같다.

#include <limits.h>
SHRT_MAX
LLONG_MAX

 

7.10 연습문제 : 크기가 표시된 자료형 사용하기

정답은 다음과 같다.

#include <stdint.h>
uint64_t

 

7.11 심사문제 : 정수형 변수 선언과 오버플로우

정답은 다음코드와 같다.

unsigned short num1;
unsigned int num2;
char num3;

 

7.12 심사문제 : 자료형 크기 구하기

sizeof(long long)의 크기는 8바이트 이므로 num1과 num2의 크기가 합쳐서 3이 되야 하므로 정답은 다음 코드와 같다.

char num1;
short num2;

 

7.13 심사문제 : 최솟값 표현하기

밑줄친 부분에 들어갈 코드는 다음과 같다.

#include <limits.h>

 

7.14 심사문제 : 크기가 표시된 정수 자료형 사용하기

밑줄친 부분에 들어갈 코드는 다음과 같다.

#include <stdint.h>

검색엔진 최적화

검색엔진은 웹 페이지를 만들어 공개하면 검색엔진 회사에서 봇(소프트웨어)를 보내어 웹 페이지 html을 다운받아 정보를 분석하여 기준에 따라 분류하여 사용자들이 검색했을 때 그 검색에 적합한 컨텐츠를 제공하는 일을 한다. 

내가 만든 컨텐츠가 사용자들이 검색 했을 때 알맞게 노출되고, 상위에 노출되도록 하기 위해 검색엔진 최적화를 해야 한다.

html코드를 의미론적 태그를 이용하여 잘 작성하는것이 검색 엔진 최적화 이다. 구글에서 제공한  검색엔진 최적화 가이드에도 의미론적 태그를 잘 사용하는것이 검색엔진 최적화를 위한 방법이라고 나와 있다.

검색엔진 최적화를 한다고 검색엔진이 좋아할 만한 것들을 너무 과하게 하면 검색엔진에서 스팸으로 판단하여 차단할 수도 있다.

구글에서 공개한 검색엔진 최적화 가이드는 다음과 같다.

search-engine-optimization-starter-guide-ko.pdf
3.58MB

검색엔진 최적화는 유료광고, 애드워즈를 제외한 기본 검색 결과에만 영향을 미친다.

 

 검색엔진들이 html사이트를 가져가서 분석할 때 title 태그를 이용하여 페이지 제목을 나타내는 것이 좋다. 

title태그는 페이지의 콘텐츠를 정확하게 설명해야 하고, 페이지마다 고유한 title태그를 작성해야 한다. 모든 웹 사이트에서 똑같은 title태그를 작성하는것은 검색엔진의 웹 페이지 분별력을 저하시키는 요소가 될 수 있다.

meta태그의 description 속성을 사용하면 검색 결과의 본문 내용에서 meta태그의 내용이 포함될 수 있다.

 description 속성으로 내용을 작성할 때는 1~2개의 문장이나 짧은 단락으로 내용을 구성하는 것이 좋다.

URL주소를 알아보기 좋은 형태로 만들면 검색엔진 최적화에도 도움이 된다.

아래 예시처럼 URL을 보고 그 페이지의 내용을 담고있는 파일 이름을 상요하는 것이 좋다.

 

 불필요한 매개변수와 세션 ID가 있는 긴 URL, 'page1.html' 과 같은 일반적인 페이지 이름, 과도하게 긴 파일 이름등은 사용하지 않는 것이 좋다. 또한 파일이 저장된 디렉터리의 구조가 너무 복잡해도 좋지 않다. 그리고 같은 컨텐츠는 한 URL에서만 접속 가능하도록 하는 것이 좋다. 같은 컨텐츠를 갖고 있는 html 파일이 2개 이상있다면 head태그 안에 link태그의 rel 속성에 "canonical"을 지정하고, href속성으로 오리지널 주소를 입력하여 검색엔진이 이 컨텐츠와 같은 오리지널 주소를 보여주도록 할 수 있다.

<link rel="canonical" href="http://localhost/1.html">

 301 리다이렉션을 이용할 수도 있다. 리다이렉션은 어떤 사이트에서 다른 사이트로 방향을 바꿔 보내버리는 것이다. 리다이렉션을 하기 위해서는 php, java등의 서버쪽의 언어를 사용해야 한다.

 

검색 엔진에서 웹 사이트의 정보를 가져가는 것을 크롤링이라고 하는데 크롤링 할 때 링크를 통해서 웹 사이트의 페이지들을 가져가기 때문에 페이지의 전체 데이터가 링크로 잘 조직화 되어 있어야 검색 엔진에서 사이트들의 데이터를 잘 가져갈 수 있다. 홈페이지는 어떠한 웹사이트의 대문 페이지를 홈페이지라고 하고, 일반적으로 파일 이름을 index.html으로 지정한다. 웹 서버를 통해 웹 사이트를 서비스 할 경우 url 주소에서 index.html을 생략해도 홈페이지에 접속이 가능하다. 이러한 홈페이지에 다른 웹사이트로 접속하는 링크들이 잘 작성이 되어 있어야 한다.

또한 사이트 이동경로를 사용하여 현재 웹페이지와 현재 웹페이지의 상위 경로들을 제공해 주는 것이 검색엔진 최적화에 도움이 된다.

사이트 내에서 쉬운 이동을 위한 권장 사항으로는 자연스러운 계층구조를 만들어야 하며 이동경로를 위해 텍스트 링크를 사용해야 한다. 사이트 이동을 할 때는 자바스크립트나 다른 방법을 이용하면 검색 엔진에서 읽지 못하는 경우가 발생할 수 있기 때문에 하이퍼 텍스트를 사용하여 사이트 이동을 하도록 하는것이 좋다.

 검색 엔진 최적화를 너무 극단적으로 추구하다 보면(예를 들어 meta태그에서 웹 사이트와 관련 없는 내용들도 많이 달아놓은 경우) 검색엔진에서 웹 스팸으로 인지하고 검색되지 않도록 차단할 수도 있다.

 a태그를 앵커라고 한다. 앵커 텍스트를 작성할 때 링크에 대한 대표성이 있는 이름으로 지정해야 한다. 앵커 텍스트를 작성할 때 '페이지', '문서' 등과 같은 일반적인 텍스트의 사용과, 페이지의 url을 텍스트로 사용하는 것을 피해야 한다. CSS등을 사용하여 링크라는것을 인지하기 힘들게 하는 행위도 피해야 한다. 링크는 사용자가 분명히 링크라는 것을 인지해야 하며, 이동되는 페이지에 대한 명확한 정보가 있는 것이 좋다.

 

이미지 관련 정보는 alt 속성을 이용하여 제공할 수 있다.

<img src="94.png" alt="생활코딩 로고">

alt 속성을 사용하면 이미지가 없거나 깨진 경우 이미지 설명을 웹 페이지에 띄워주며 시각장애인용 스크린 리더에서는 alt속성의 값을 읽어줘서 어떤 내용을 가진 이미지인지 알 수 있도록 할 수 있다. 구글 이미지 검색에서도 검색엔진이 이미지를 더 쉽게 이해할 수 있게 된다.
또한 이미지를 저장할 때는 'images' 라는 이름을 가진 디렉터리에 사용할 이미지들을 모아서 저장하고 사용한다.

이미지를 사용할 때는 일반적인 이름보다는 의미를 가진 이름을 사용하는것이 좋다.

img 태그를 a태그로 감싸서 이미지를 링크로 사용할 때 alt를 사용하면 위에서 설명한 앵커텍스트를 활용한 것과 비슷한 효과를 가질 수 있다.

 제목태그는 웹 페이지에서 중요한 내용을 강조할 때 사용하는 태그이며 블로그나 게시판 등의 에디터를 이용할 때는 제목 기능을 이용하고 웹 소스를 보면 제목 태그가 사용된 것을 확인할 수 있다.

 

 robots.txt는 나의 웹사이트를 크롤링 하기 위해 들어오는 로봇들의 접근 허용 또는 거부, 허용 범위등의 정보를 명시하는 파일이다.

위의 robots.txt는 네이버의 것이다. 네이버는 Disallow: / 을 사용하고 있는데 /은 네이버의 모든 웹페이지를 의미하며 네이버의 모든 웹페이지는 로봇의 접근을 거부한다는 의미이다. 네이버에서 만들어진 컨텐츠는 다른 검색 엔진에서 접근할 수 없음을 의미한다.

위의 robots.txt는 구글의 것이다. 구글도 로봇의 접근을 허용하는 페이지들은 Allow로, 허용하지 않는 페이지들은 Disallow로 표시하고 있다.

robots.txt는 검색 엔진들에게 요청하는 방식이기 때문에 악의적인 목적을 가진 로봇들은 요청에 응해주지 않기 때문에 보안의 목적으로는 사용하면 안된다. 민감한 페이지들은 다른 방식을 이용하여 원천적으로 차단해야 한다.

 opentutorials의 sitemap 페이지를 보면 다음과 같다.

sitemap은 웹 사이트의 지도로 사용자들에게 사이트 전체에 대한 구조를 보여주는 ui이다. 사이트 맵은 사람들이 보기 쉬운 방식과 기계들(검색엔진, 크롤러 등)이 보기 쉬운 방식의 두 가지 방식의 사이트맵이 있다.

사이트맵은 위와 같이 url 태그 안의 loc 태그 안에 웹 사이트의 페이지들을 각각 입력하고 robots.txt의 Sitemap: 에 만든 사이트맵 페이지의 파일 이름을 넣어주면 된다. 그렇게 하면 검색엔진의 로봇 등이 robots.txt를 확인하고 사이트맵 페이지에 접속하여 사이트 맵 페이지를 읽고 활용하는 작업을 진행한다. 

 

페이지 랭크는 똑같은 단어를 가진 두 개의 사이트가 있을 때 어떤 사이트를 먼저 검색 결과로 노출할지의 기준이 되는 것이다. 구글은 전 세계의 모든 사이트에 페이지 랭크를 매기고 검색했을때 더 높은 랭크를 가진 사이트가 먼저 노출된다.

A와 B라는 두 사이트가 있고, 다음과 같이 A사이트를 링크하고 있는 다른 사이트들이 많지만, B사이트를 링크하고 있는 다른 사이트 들은 없을 때 페이지 랭크의 순위는 A가 더 높아진다.

이때 A와 B모두 가지고 있는 정보를 검색하게 되면 A의 랭크가 더 높기 때문에 A의 노출 우선순위가 더 높아진다. 

많은 사이트들이 링크하고 있는 사이트라면 그 사이트는 더 좋은 컨텐츠를 갖고 있는 사이트일 확률이 높다 라는 전제가 있는 것이다.

A 사이트가 다른 사이트를 링크를 걸면 A 사이트의 랭크가 높기 때문에 그 사이트의 랭크도 상당히 높이 올라간다. 이는 링크, 하이퍼 텍스트의 중요성을 잘 보여주기도 한다.

meta

meta 데이터는 어떠한 데이터를 설명하는 데이터이다. 웹 페이지를 만들 때 웹 페이지의 전체를 설명하는 메타 데이터가 있다.(웹 페이지의 저자, 제목 등)

이러한 정보들을 표현할 때 쓰는 것이 <meta>태그이다.

지금까지 <meta> 태그의 charset속성에서 "utf-8"을 지정해 준 것은 해당 문서를 저장할 때 인코딩 방식을 utf-8으로 저장된 문서라고 알려주는 것이고, 웹 브라우저는 저 태그를 보고 utf-8으로 해석하여 웹 페이지를 보여준다.

<meta>태그의 name 속성에 "description" 을 지정하고, content속성에 요약된 정보를 작성하면 웹 페이지에는 표현하지 않지만 검색엔진 등에서 사용하는 요약 자료로 사용하도록 할 수 있다.

<meta>태그의 name 속성에 "kewords"를 지정하고, content 속성에 키워드들을 작성하면 웹 페이지를 분류할 때 키워드를 참고해서 분류할 수 있다

<meta>태그의 name 속성에 "author"을 지정하면 content 속성에 웹 페이지의 저자를 작성하여 저자를 설명할 수 있다.

<meta>태그의 http-equiv 속성에 "refresh"를 지정하고, content 속성에 숫자를 지정하면 지정한 숫자 초 만큼 시간이 지난 후에 웹 페이지를 리프레쉬 하는 효과를 사용할 수 있다.

<html>
<head>
    <meta charset="utf-8">
    <meta name="description" content="생활코딩의 소개 자료">
    <meta name="kewords" content="코딩, 생활코딩, 프로그래밍, html">
    <meta name="author" content="phulasso">
    <meta http-equiv="refresh" content="30">
</head>
<body>
    생활 코딩은 일반인에게 ~~~~~~ 입니다.
</body>
</html>

 

의미론적 태그

semantic은 '의미론적인' 이라는 뜻이다. html에 표현되는 정보들이 의미에 맞게 표현할 수 있도록 해주는 태그들을 semantic 태그라고 한다.

html5에서 추가된 sementic 태그들은 다음과 같다.

<html>
<head>
    <title>HTML - 수업</title>
    <meta charset="utf-8">
</head>

<body>
    <h1><a href="index.html">HTML</a></h1>
    <ol>
        <li><a href=1.html>기술소개</a></li>
        <li><a href=2.html>기본문법</a></li>
        <li><a href=3.html>하이퍼텍스트와 속성</a></li>
        <li><a href=4.html>리스트와 태그의 중첩</a></li>
    </ol>

    <h2>hello world</h2>
</body>
</html>

위 html 문서를 의미론적 태그를 사용하여 작성하면 다음과 같다.

<html>
<head>
    <title>HTML - 수업</title>
    <meta charset="utf-8">
</head>

<body>
    <header>
        <h1><a href="index.html">HTML</a></h1>
    </header>
    <nav>
        <ol>
            <li><a href=1.html>기술소개</a></li>
            <li><a href=2.html>기본문법</a></li>
            <li><a href=3.html>하이퍼텍스트와 속성</a></li>
            <li><a href=4.html>리스트와 태그의 중첩</a></li>
        </ol>
    </nav>
    <section>
        <article>
            <h2>hello world</h2>
            본문~~~~~~~~~~~~~~~~~~~
        </article>
        <article>
            <h2>hello world</h2>
            본문~~~~~~~~~~~~~~~~~~~
        </article>
        <article>
            <h2>hello world</h2>
            본문~~~~~~~~~~~~~~~~~~~
        </article>
        <article>
            <h2>hello world</h2>
            본문~~~~~~~~~~~~~~~~~~~
        </article>
    </section>
    <footer>
        <ul>
        <li><a href="privacy.html">개인 보호 정책</a></li>
        <li><a href="about.html">회사소개</a></li>
        </ul>
    </footer>
</body>
</html>

의미론적 태그들을 사용하면서 시각적으로 달라지는 부분들은 없다. 시각적인 기능은 없고 의미만을 갖고 있는 태그들이다.

<header>태그는 웹 페이지에서 헤더에 해당하는 부분, 사이트의 전체의 정보가 표현된 부분에서 사용한다.

<footer>태그는 header 태그가 있는 웹 페이지에는 대부분 있는데 웹 페이지에 대한 부가적인 설명들이 들어가며 웹사이트 제일 하단에 사용한다.

<nav> 태그는 웹 페이지에서 컨텐츠를 탐색할 때 사용하는 네비게이션 역활을 하는 부분에 사용된다.

<article> 태그는 웹 페이지의 본문에 해당하는 부분에서 사용된다. 웹 페이지에 따라서 본문이 여러개이면 article태그를 여러개 사용할 수 도 있다.

<section>태그를 이용하여 여러개의 article태그를 같은 섹션으로 묶어줄 수 있다. section 태그는 header, nav등과 달리 특정한 역할로 정의하기 어려운 섹션들을 묶어줄 때 사용한다.

method

폼의 기능은 브라우저에 사용자가 입력한 정보를 서버쪽으로 전송하는 것이다.

서버로 전송하는 방식에는 get 방식과 post방식이 있다.

get 방식은 정보를 url에 넣어서 서버로 전송하는 방식이다.

<html>
<head>
    <meta charset="utf-8">
</head>
<body>
    <form action="http://localhost/method.php">
        <input type="text" name="id">
        <input type="password" name="pwd">
        <input type="submit">
    </form>
</body>
</html>

get 방식을 사용하면 위와 같이 url의 ?뒤에 입력한 정보가 들어가서 서버로 전송된다.

get 방식을 사용하면 비밀번호 같이 민감한 정보도 url에 노출되어 위험할 수 있다. 그래서 post 방식을 사용해야 한다. post 방식은 <form>태그에 method속성을 추가하여 속성값을 "post"로 설정한다. 속성값을 "get"로 설정하거나 method속성을 추가하지 않으면 기본적으로 get방식으로 전송된다.

<html>
<head>
    <meta charset="utf-8">
</head>
<body>
    <form action="http://localhost/method.php" method="post">
        <input type="text" name="id">
        <input type="password" name="pwd">
        <input type="submit">
    </form>
</body>
</html>

post 방식을 사용하면 url 뒤에 아무런 정보도 없이 폼에서 입력한 값을 감춰서 서버로 전송한다. 따라서 굳이 get 방식을 사용할 이유가 없다면 post 방식을 사용하는것이 더 안전할 수 있다.

 

파일 업로드

웹 페이지에서 파일 업로드는 <input> 태그의 type 속성의 값으로 "file"을 사용한다. <form>태그 안의 <input>태그에서 파일을 업로드 한 뒤, 서버로 전송하면 이후 파일에 대한 처리는 서버에서 처리한다. form으로 서버로 파일을 전송할 때는 <form>태그에서 method속성 값을 "post"로 설정해야 하고, enctype 속성 값을 "multipart/form-data"로 설정해야 한다.

<html>
<head>
    <meta charset="utf-8">
</head>
<body>
    <form action="http://localhost/upload.php" method="post" enctype="multipart/form-data">
        <input type="file" name="profile">
        <input type="submit">
    </form>
</body>
</html>

파일을 선택하여 제출 버튼을 누르면 form 태그의 action속성에서 지정한 서버로 파일이 전송된다.

 

정보로서의 HTML

웹의 성장에 따라 인류의 많은 정보들이 웹으로 표현되며 html의 중요성이 더 커지고 있다. 

정보를 더 잘표현하기 위해 여러가지 조치들이 취해졌다.

 

글꼴 - font (퇴출됨)

현 시점에서 font 태그는 퇴출되었다. 퇴출되었지만 아직까지도 통계적으로 font태그를 사용하는 곳이 많이 존재한다.

<font>태그는 size 속성으로 글자의 크기를 정할 수 있다. 글자 크기는 작은 순서대로 1~7까지 설정할 수 있다. color 속성으로 글씨의 색을 정할 수 도 있다.

<html>
<head>
    <meta charset="utf-8">
</head>
<body>
    <font size="7" color="red">Hello</font> World
    <font size="7" color="red">Hello</font> World
    <font size="7" color="red">Hello</font> World
    <font size="7" color="red">Hello</font> World
</body>
</html>

font태그는 다른 태그들 처럼 html의 기능에 집중한 태그가 아닌 디자인에 집중되어 있는 태그이다. html을 정보를 전달하는 기능에 집중하여 사용하기 위해 디자인 관련한 태그들은 퇴출시키고 웹 페이지의 디자인을 위한 언어인 CSS를 만들었다. font태그를 사용하게 되면 이 태그는 정보에 대한 설명을 하고 있지 않으며, 이 태그로 디자인을 사용하게 되면 html의 파일 용량도 커지며 정보로써 html 파일을 해석하기 어려워지는 문제점들을 갖고 있기 때문에 사용하지 않는 것이 좋다.

텍스트 입력

<input>태그의 type 속성에 "text"를 입력하면 사용자로부터 텍스트를 입력받는 곳을 만들 수 있다. "password"속성을 입력하면 패스워드 입력란 처럼 사용자의 입력값의 내용을 확인할 수 없도록 할 수 있다.

input태그는 서버로 값을 전송할때 많이 쓰기 때문에 서버에서 값을 인식할 수 있도록 name 속성을 꼭 사용해 줘야 한다.

value 속성에 값을 넣으면 기본 값을 설정해 줄 수 있다.

텍스트 입력값을 여러줄로 받고 싶을 때는 <textarea> 태그를 사용하면 된다. 

cols 속성을 사용하면 폭을 지정해 줄 수 있고, rows속성을 사용하면 높이를 지정해 줄 수 있다.

textarea태그에서 기본 값을 설정해주려면 태그 안에 값을 넣으면 된다.

<html>
<body>
    <form action="">
        <p>text : <input type="text" name="id" value="default value"></p>
        <p>password : <input type="password" name="pwd" value="default value"></p>
        <p>textarea : 
            <textarea cols="50" rows="2">default value</textarea>
        </p>
    </form>
</body>
</html>

 

선택

사용자들에게 여러가지 선택지 중 하나를 선택하게 하는 방법중 Dropdown List 라는 방법이 있다. Dropdown List는 제한된 공간 안에서 여러개의 선택지 중 하나를 선택하는 방법이다. 

<select> 태그 안에 <option> 태그를 사용하여 선택하는 태그를 만들 수 있다. 이렇게 사용하면 선택지 중에 하나만 선택할 수 있다.

선택지 중에 여러개를 선택하도록 만들고 싶다면 <select> 태그에서 multiple 속성을 사용해야 한다. 이 속성은 속성값이 없이 속성만 사용한다. 여러개를 선택할 때는 Ctrl키를 누른 후 선택할 항목을 클릭하면 된다.

선택한 정보를 서버로 전송하기 위해서는 역시 <form> 태그를 사용해야 한다. 

서버로 전송할 때 선택한 정보를 컴퓨터가 더 이해하기 쉽도록 하려면 value 태그를 이용하여 서버로 전송할 값을 따로 지정해 줄 수 있다.

<html>
<head>
    <meta charest="utf-8">
</head>
<body>
    <form action="http://localhost/color.php">
        <h1>색상</h1>
        <select name="color">
            <option value="red">붉은색</option>
            <option value="black">검은색</option>
            <option value="blue">파란색</option>
        </select>
        <h1>색상2 다중선택</h1>
        <select name="color2" multiple>
            <option value="red">붉은색</option>
            <option value="black">검은색</option>
            <option value="blue">파란색</option>
        </select>
        <input type="submit">
    </form>
</body>
</html>

서버로 전송되는 값을 보면 color2는 여러개의 색상이 전송되어 있고, 모두 value속성에서 지정한 값으로 전송되는 것을 확인할 수 있다.

 

버튼

<input> 태그의 type 속성에 "submit"을 지정하면 클릭했을 때 서버로 폼의 내용이 전송되는 버튼을 만들 수 있다. 버튼 안의 글자는 value 속성을 이용하여 바꿀 수 있다.

type 속성에 "button"을 지정하면 어떤 효과도 갖지 않는 버튼을 만들 수 있다. 이 버튼은 onclick속성을 이용하여 클릭했을 때의 효과를 지정해 줄 수 있다. 아래 코드에서는 자바스크립트로 클릭시 경고창을 띄우는 기능을 지정하였다.

type 속성에 "reset"을 지정하면 클릭시 폼에 작성한 내용들이 모두 초기화 되는 버튼을 만들 수 있다.

<html>
<head><meta charset="utf-8"></head>
<body>
    <form action="http://localhost/form.php">
        <input type="text">
        <input type="submit" value="전송">
        <input type="button" value="버튼" onclick="alert('hello')">
        <input type="reset">
    </form>
</body>
</html>

위는 버튼을 클릭했을시 자바스크립트로 지정한 경고창이다.

 

데이터 전송 - hidden

서버로 데이터를 전송할 때 UI가 굳이 필요 없거나 데이터를 몰래 전송해야 할 경우 hidden을 사용한다.

<input>태그의 type속성에 "hidden"을 지정해 주면 된다. value 속성에 서버로 전송할 값을 넣는다.

<html>
<head>
    <meta charset="utf-8">
</head>
<body>
    <form action="http://localhost/hidden.php">
        <input type="text" name="id">
        <input type="hidden" name="hide" value="phulasso">
        <input type="submit"> 
    </form>
</body>
</html>

웹 페이지를 보면 ui에서 hidden 속성을 사용한 input태그는 보이지 않는다. 하지만 값을 넣어서 전송해보면 다음과 같이 hidden 속성의 value 값이 서버로 전송되는 것을 확인할 수 있다.

 

컨트롤의 제목 - lable

input 태그의 이름을 정할 때 html에서 권장하는 방법은 <lable>태그를 사용하는 것이다. input 태그의 이름을 <lable>태그로 감싸면 된다.

어떤 input태그의 이름인지 확실하게 명시하기 위해서 input 태그에 id라는 속성을 넣어 값을 지정하고, lable 태그의 for 속성에 input 태그에서 지정한 id값을 넣어야 한다.

아니면 lable 태그로 input태그의 이름과 input태그까지 같이 감싸도 된다.

lable 태그를 사용하게 되면 input 태그의 이름을 클릭해도 해당 input 태그가 선택되고, 체크박스인 경우 이름만 클릭해도 체크박스가 체크된다. 

<html>
<body>
    <form action="">
        <p>
            <label for="id_txt">text :</label> 
            <input id="id_txt" type="text" name="id" value="default value">
        </p>
        <p>
            <label for="password">password :</label> 
            <input id="password" type="password" name="pwd" value="default value">
        </p>
        <p>
            <label>textarea : 
                <textarea cols="50" rows="2">default value</textarea>
            </label>
        </p>
        <p>
            <label>
                <input type="checkbox" name="color" value="red"> 붉은색
            </label>
            <label for="color_blue">
                <input id="color_blue" type="checkbox" name="color" value="blue"> 파란색
            </label>
        </p>
    </form>
</body>
</html>

 

줄바꿈 - br

p 태그는 줄바꿈의 간격이 고정되어 있기 때문에 <br>태그를 이용하면 자유롭게 줄바꿈을 이용할 수 있다. <br>태그는 내용이 없는 태그이기 때문에 열리는 태그 하나만 있으면 된다. <br>태그의 개수에 따라 줄바꿈 횟수도 결정되어 간격도 더 커진다.

<html>
<body>
    hello<br>
    world<br><br><br>
    br 태그
</body>
</html>

 

이미지 - img

웹 페이지에 이미지를 넣을 때는 img 태그를 사용한다. imf태그도 닫는 태그 필요 없이, 여는 태그만 있으면 된다.

src 속성으로 이미지 이름을 지정하고, width 속성과 height 속성으로 이미지 크기를 지정한다. 이미지는 원래 크기가 정해져 있기 때문에 width와 height 속성을 모두 사용하면 왜곡되는 현상이 발생할 수 있다. 이 둘중 하나의 속성만 사용하면 그 크기와 맞게 원본 이미지의 비율로 크기를 수정할 수있다.

alt 속성을 사용하면 이미지 손상 등의 이유로 웹 페이지에서 보여줄 수 없을 때 이미지가 깨진 아이콘과 원래 이미지에 대한 설명을 보여줄 수 있다. 

title 속성을 사용하면 이미지에 마우스 커서를 대면 title 속성값을 보여준다.

<html>
<body>
    <img src="mountain.jpg"  height="300" alt="mountain img" title="산이미지">
</body>
</html>

 

이미지 파일을 불러올 수 없는 경우

 

표 - table

이름 성별 주소
phulasso seoul

위와 같은 표도 웹 페이지에 삽입할 수 있다. 

각 칸에 들어가는 내용들은 <td>태그 안에 넣는다. td는 table data라는 의미이다.

각 열은 <tr>태그로 구분한다. tr은 table row라는 의미이다. td태그들은 테이블의 열에 맞게 tr태그 안에 들어간다.

td를 포함한 tr 태그는 <table> 태그 안에 들어간다. table 태그의 border 속성을 이용하여 표의 구분 선도 만들 수 있다. border속성의 값이 커질 수록 선의 굵기가 굵어진다.

<html>
<body>
    <table border="1">
        <tr>
            <td>이름</td> <td>성별</td> <td>주소</td>
        </tr>
        <tr>
            <td>lee</td> <td>남</td> <td>서울</td>
        </tr>
        <tr>
            <td>kim</td> <td>여</td> <td>청주</td>
        </tr>
    </table>
</body>
</html>

과거에는 웹 페이지의 레이아웃을 잡을 때 테이블 태그를 이용하여 표로 구성하기도 했다.

위의 표를 보면 이름, 성별, 주소가 있는 열은 표의 제목에 해당하는 부분이다. 이 열은 tr 태그 밖에 <thead> 태그로 감싸준다. thead태그 안에 있는 각 칸의 데이터들은 <th>태그를 이용하면 글씨를 볼드체로 굵게 만들 수 있다.

그 밑의 두 줄은 표 내용의 본문에 해당한다. 이 열들은 tr 태그 밖에 <tbody> 태그로 감싸준다. 

테이블의 가장 밑 줄은 <tfoot>태그로 감싸주면 된다. thead, tbody, tfoot태그는 표의 모양을 직접적으로 변화시키지 않지만 태그만 보고 표의 구조를 파악하는데 도움을 주며 표를 더 체계적으로 만드는데 도움을 주므로 꼭 사용하는 것이 좋다. 

thead 태그와 tfoot 태그는 테이블의 중간에 들어가도 웹 페이지에 나오는 표를 보면 항상 표의 맨 위와 맨 아래에 위치하는 자리를 결정하는 역할도 한다.

<html>
<body>
    <table border="1">
        <thead>
            <tr>
                <th>이름</th> <th>성별</th> <th>주소</th> <th>회비</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>lee</td> <td>남</td> <td>서울</td> <td>1000</td>
            </tr>
            <tr>
                <td>kim</td> <td>여</td> <td>청주</td> <td>500</td>
            </tr>
        </tbody>
        <tfoot>
            <tr>
                <td>합계</td> <td></td> <td></td> <td>1500</td>
            </tr>
        </tfoot>
    </table>
</body>
</html>

표의 각 칸을 병합하고 싶을 때는 td태그의 속성을 사용하면 된다. rowspan 속성은 속성 값만큼 수직으로 병합하며 병합되는 칸에 해당하는 td태그는 지워줘야 한다. colspan 속성은 속성 값 만큼 수평으로 병합되며 병합되는 칸에 해당하는 td태그는 지워줘야 한다.

<html>
<body>
    <table border="1">
        <thead>
            <tr>
                <th>이름</th> <th>성별</th> <th>주소</th> <th>회비</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>lee</td> <td>남</td> <td rowspan="2">서울</td> <td>1000</td>
            </tr>
            <tr>
                <td>kim</td> <td>여</td> <td>500</td>
            </tr>
        </tbody>
        <tfoot>
            <tr>
                <td colspan="3">합계</td> <td>1500</td>
            </tr>
        </tfoot>
    </table>
</body>
</html>

 

입력양식 - form

로그인, 회원가입, 글작성 등을 할 때 서버로 정보를 전송하기 위해 사용하는 글자를 입력하는 곳, 선택하는 곳 등을 form(폼) 이라 한다.

<input>태그를 이용하면 웹 페이지 이용자가 작성할 수 있는 텍스트 상자를 만들 수 있다. input 태그의 type의 속성을 "text"로 지정해 주면 된다.

type 속성을 "password"로 지정해주면 로그인할 때 비밀번호를 작성하는 곳처럼 내용이 보이지 않는 텍스트 상자를 만들 수 있다.

type 속성을 "submit"으로 지정하면 제출 버튼을 만들 수 있다.

이러한 input태그들은 <form> 태그 안에 넣어야 한다. input 태그에 작성한 내용들은 form 태그의 action속성 안에 지정한 서버로 전송한다.

같은 type 속성이 여러 개 있는 경우 서버에서는 각 태그를 구분할 수 없기 때문에 name 속성을 이용하여 구분해준다.

<html>
<body>
    <form action="http://localhost/login.php">
        <p>아이디 : <input type="text" name="id"></p>
        <p>비밀번호: <input type="password" name="pw"></p>
        <p>주소 : <input type="text" name="addr"></p>
        <input type="submit">
    </form>
</body>
</html>

 

 

기술소개

HTML : Hyper Text Markup Language

Hyper Text : 링크와 같은기능

Markup : 문법적인 형식 

-> 하이퍼텍스트를 가장 중요한 특징으로 하는 마크업 형식을 가진 프로그래밍 언어

Language : 언어

언어의 핵심은 약속이다. 약속을 공유하고 있기 때문에 서로 소통이 가능하다.

기계를 제어하고 싶으면 사람도 이해할 수 있고, 기계도 이해할 수 있는 약속이 필요하며 이를 언어라고 부른다.

HTML은 웹 브라우저에 표시되는 웹 페이지를 컴퓨터에게 만들어달라고 표현하는 언어이다.

사람과 웹 브라우저 사이에서 모두가 이해 가능한 약속(언어)이다.

웹 브라우저에서 우클릭 -> 페이지 소스 보기를 클릭하면 나오는 문자들이 HTML 코드 이다.

 

기본 문법

태그 : HTML에서 가장 중요한 문법이며 Markup가 태그와 밀접한 관계를 가진다.

텍스트 파일에 내용을 넣고, 인코딩은 utf-8 로 하고, 확장자는 .html 확장자를 사용하여야 한다.

확장자가 html이면 파일을 더블클릭 했을 때 웹 브라우저가 열린다. 운영체제가 해당 확장자를 열 프로그램을 미리 지정하고 있기 때문이다.

텍스트 편집기에 입력된 내용을 웹 브라우저가 화면에 표시해주고 있다.

<strong> </strong>안에 있는 내용은 글씨가 굵게 강조되어 표시된다. 이러한 것들을 태그라 그러고, <strong>를 시작태그 , </strong>를 닫히는 태그라 한다. 시작 태그에서 닫히는 태그 안에 있는 내용을 강조하는 것이다.

웹 브라우저에서는 텍스트 편집기에서 입력한 줄바꿈이 적용되지 않는다.

위와 같이 <h1>태그를 사용하면 제목을 적을 수 있다. h1은 heading 1 이라는 뜻이다. 웹 브라우저는 h1이라는 태그가 사용되면 굵고 큰 글씨로 표현되고, 줄을 바꾼다고 약속되어 있기 때문에  h1 태그를 작성하면 위와 같이 표현한다. 더 작은 제목을 쓰고 싶으면 h2를 사용하면 된다.

태그는 꺽쇠로 시작하고, 꺽쇠 안 태그 이름에 슬래시를 붙인다.

 

하이퍼텍스트와 속성

a 라는 태그로 다른 웹사이트의 링크를 달 수 있다. 연결될 웹 페이지의 url을  a 뒤 href=""에 넣어야 한다. href와 같은것을 속성 이라고 한다.

웹 페이지에 링크가 생기며 클릭하면 href속성에 작성한 url로 페이지가 이동된다.

위와 같이 target 라는 속성에 "_blank"를 넣으면 새 탭에서 연결된 url 페이지가 열린다. 속성의 순서는 상관 없고, 속성에 따라서 태그의 기능이 추가된다.

a 태그는 문서와 문서가 연결되는 하이퍼 텍스트를 구현한 것이다. a태그는 anchor에서 가져온 것이다. anchor은 배의 닻이라는 의미를 갖고 있고, 연결할 url에 정박해 있다는 의미일 것이다.

GML -> SGML -> SGMLguid -> HTML의 순서로 HTML이 발전하였다. 

 

태그의 중첩과 목록

각각의 항목들을 리스트로 표현하려면 <li>라는 태그를 사용한다.

<li> 태그를 사용하면 각각의 항목들이 시각적으로 구분되게 사용할 수 있다.

서로 성격이 같은 태그들을 다음과 같이 <ul>태그로 묶으면 <ul>태그로 묶인 태그끼리 구분할 수 있다.

위와 같이 태그 안에 태그를 넣어 중첩하여 사용할 수도 있다. 위와  같은 방식으로 사용하면 태그가 복잡해질수록 읽기 힘들어 지기 때문에 들여쓰기를 사용하여 가독성을 높여줄 수도 있다.

위에 있는 순서가 있는 리스트로 표현하려면 ul을 ol로 바꿔 주면 된다.

li 는 list의 약자이고, ol은 ordered list의 약자이고, ul은 unordered list의 약자이다.

 

문서의 구조

<title> 태그를 사용하면 탭의 제목을 정해줄 수 있다. <meta charset="utf-8">을 사용하면 문서가 깨질 경우를 방지할 수 있다.

<title>HTML - 수업</title>
<meta charset="utf-8">

<h1>HTML</h1>
<ol>
    <li>기술소개</li>
    <li>기본문법</li>
    <li>하이퍼텍스트와 속성</li>
    <li>리스트와 태그의 중첩</li>
</ol>

<h2>hello world</h2>

html 문서의 위 두줄은 본문과는 관계없는 부가적인 내용들을 담고 있고, 그 아래부터는 본문의 내용들을 담고 있다. 

html에서는 문서의 부가적인 정보들과 본문에 해당하는 정보들을 각각 다른 태그에 담도록 약속하고 있다.

본문이 아닌 태그들과 본문인 태그들은 head태그와 body 태그로 구분하기로 약속하고 있다.

또한 문서의 가장 바깥에 html 태그를 두어 그 안에 head 태그와 body 태그를 담기로 약속되어 있다.

<html>
<head>
    <title>HTML - 수업</title>
    <meta charset="utf-8">
</head>

<body>
    <h1>HTML</h1>
    <ol>
        <li>기술소개</li>
        <li>기본문법</li>
        <li>하이퍼텍스트와 속성</li>
        <li>리스트와 태그의 중첩</li>
    </ol>

    <h2>hello world</h2>
</body>
</html>

 

DOCTYPE

DOCTYPE은  html문서의 시작 부분에 <!DOCTYPE html>이라는 태그를 넣어 줘야 한다. 

DOCTYPE은 Document type declaration의 약자이다. 어떤 방식으로 html코드를 작성했는지 브라우저에게 알려주는 문자이다. 어떠한 표준에 따라 문서를 작성했는지 알려주는 역할을 한다.

 

웹사이트 만들기

<html>
<head>
    <title>HTML - 수업</title>
    <meta charset="utf-8">
</head>

<body>
    <h1><a href="index.html">HTML</a></h1>
    <ol>
        <li><a href=1.html>기술소개</a></li>
        <li><a href=2.html>기본문법</a></li>
        <li><a href=3.html>하이퍼텍스트와 속성</a></li>
        <li><a href=4.html>리스트와 태그의 중첩</a></li>
    </ol>

    <h2>hello world</h2>
</body>
</html>

위와 같은 li 태그의 내용에  a태그로 링크를 걸어서 각 페이지 마다 다른 내용을 웹 브라우저에서 보여주는 웹 사이트를 만들 수 있다. 이 실습에서는 본문은 다 동일하게 하고 페이지 구분을 위해 h2 태그의 내용만 수정하였다. 다음은 기본문법에 링크된 페이지(2.html) 이다.

 

개발도구

html을 사용하여 웹 페이지를 만들 때 사용하는 도구(프로그램)이다. 개발 도구에는 atom, sublime text, bracket등이 있다. 나는 개발도구로 vscode를 사용할 것이다.

 

HTML의 변천사와 통계

www.martinrinehart.com/frontend-engineering/engineers/html/html-tag-history.html

 

HTML Tag History

HTML Tags: Past, Present, Proposed © 2012, Martin Rinehart Prerequisite: This page was prepared for students learning from Professional HTML, Volume I of V in the Frontend Engineering series. It is most meaningful to persons currently using HTML who wish

www.martinrinehart.com

위 사이트는 html 버전의 태그들이 어느 버전때 생겨났고, 어느 버전때 사라지게 된 태그들이 있는지 확인할 수 있는 html 연대기 사이트 이다.

www.advancedwebranking.com/html/

 

The average web page from top twenty Google results

Apparently, an average web page uses thirty-two different element types: The thirty-two elements used on most pages, ordered by appearance frequency:

www.advancedwebranking.com

위 사이트는 구글에서 분석한 웹 페이지에서 html태그를 얼마나 많이 사용하는가? 어떤 태그들이 웹 페이지에서 많이 등장하는가? 등의 html의 태그에 관련된 통계를 확인할 수 있다.

 

주요태그

단락 - p

p 태그는 paragraph의 줄임말로 단락을 구분할 때 사용한다. 단락은 줄바꿈과 약간의 여백으로 구분한다.

<html>
    <body>
        <p> 
        Hypertext Markup Language (HTML) is the standard markup language for documents designed to be displayed in a web browser. 
        It can be assisted by technologies such as Cascading Style Sheets (CSS) and scripting languages such as JavaScript.
        </p>
        <p>
        Web browsers receive HTML documents from a web server or from local storage and render the documents into multimedia web pages. 
        HTML describes the structure of a web page semantically and originally included cues for the appearance of the document.
        HTML elements are the building blocks of HTML pages.
        </p>
        <p>
        With HTML constructs, images and other objects such as interactive forms may be embedded into the rendered page. 
        HTML provides a means to create structured documents by denoting structural semantics for text such as headings, paragraphs, lists, links, quotes and other items. 
        HTML elements are delineated by tags, written using angle brackets.
        </p>
    </body>
</html>

p 태그를 사용하면 웹 페이지에서 단락을 구분할 수 있다. 단락간의 간격은 CSS를 통해서 변경시킬 수 도 있다.

1097 : [기초-2차원배열] 바둑알 십자 뒤집기(설명)

처음 바둑판 상태를 입력받고, 뒤집기할 횟수를 입력받고, 좌표를 입력받는다.  반복문으로 반복하며 좌표의 가로줄과 세로줄의 흑, 백을 변환한다. 처음 바둑판 상태는 판 리스트를 하나 만들어 두고, 입력값 각 줄을 리스트로 만들어 기존에 만들어둔 리스트에 넣어 2차원 리스트로 만들었다. 십자 뒤집기는 입력받은 좌표의 세로줄과 가로줄 각각 반복문으로 19번 반복하며 흑과 백을 변환하였다.

pan = []
# 바둑판 초기 상태 입력
for i in range(19):
    a = list(map(int, input().split()))
    pan.append(a)

n = int(input())

for i in range(n):
    # 십자 뒤집기 할 좌표
    x, y = map(int, input().split())
    # 리스트 인덱스는 0번부터 시작하므로 1씩 빼줌
    x -= 1
    y -= 1
    # 가로 줄 흑, 백 변환
    for j in range(19):
        if pan[x][j] == 0:
            pan[x][j] = 1
        else:
            pan[x][j] = 0
    # 세로줄 흑, 백 변환
    for j in range(19):
        if pan[j][y] == 0:
            pan[j][y] = 1
        else:
            pan[j][y] = 0

# 최종 값 출력
for i in range(19):
    for j in range(19):
        print(pan[i][j], end = ' ')
    print()

 

1098 : [기초-2차원배열] 설탕 과자 뽑기

입력받은 가로, 세로 크기 만큼 0을 채운 격자판을 2차원 리스트로 만들고, 길이, 방향, 좌표를 입력받아 입력받은 좌표부터 가로 또는 세로 방향으로 입력받은 길이까지 1로 채우는 행위를 입력받은 좌표 수만큼 반복하고, 막대가 채워진 최종 격자판을 출력한다.

h, w = map(int, input().split())
pan = []

# 격자판 초기상태(모든 칸 0)
for i in range(h):
    pan.append([0] * w)

n = int(input())
for i in range(n):
    l, d, x, y = map(int, input().split())
    x -= 1
    y -= 1
    # 막대가 가로로 놓여있을 때
    if d == 0:
    	# 시작 좌표부터 가로 길이만큼 1로 채워짐
        for j in range(l):
            pan[x][y+j] = 1
    # 세로로 놓여있을 때
    else:
        # 시작 좌표부터 세로 길이만큼 1로 채워짐
        for j in range(l):
            pan[x+j][y] = 1

# 격자판 채운 모양 출력
for i in range(h):
    for j in range(w):
        print(pan[i][j], end = ' ')
    print()

 

1099 : [기초-2차원배열] 설탕 과자 뽑기

리스트의 인덱스는 0부터 시작하기 때문에 시작 인덱스를 1,1 로 지정하였고, 입력값은 한 줄씩 리스트로 만들어 입력받아 2차원 리스트로ㅓ 만들었다. 무한 루프 반복문을 만들어 개미가 먹이를 만나거나, 오른쪽 또는 아래로 이동할 수 없을 때 반복문을 탈출하도록 하였고, 벽이 없으면 오른쪽으로 벽이 있으면 아래로 이동하면서 현재 위치에 9를 저장하였다.

miro = []
x, y = 1, 1
for i in range(10):
    a = list(map(int, input().split()))
    miro.append(a)

while True:
    if miro[x][y] == 2:
        miro[x][y] = 9
        break
    miro[x][y] = 9
    if miro[x][y+1] == 0:
        y += 1
    elif miro[x][y+1] == 1:
        if miro[x+1][y] == 1:
            break
        elif miro[x+1][y] == 2:
            miro[x+1][y] = 9
            break
        else:
            x += 1
    else:
        miro[x][y+1] = 9
        break



for i in range(10):
    for j in range(10):
        print(miro[i][j], end = ' ')
    print()

+ Recent posts